Skip to content

Commit

Permalink
Merge pull request #21 from oarepo/corovcam/fe-150-ux-for-requests-bu…
Browse files Browse the repository at this point in the history
…ttons-in-various-dialogues

UX for request buttons in various dialogues + Refactor RequestModal.jsx
  • Loading branch information
mirekys authored Jun 19, 2024
2 parents 36394df + 0963abb commit 0ad0f2b
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 102 deletions.
Binary file modified oarepo_requests/translations/cs/LC_MESSAGES/messages.mo
Binary file not shown.
20 changes: 18 additions & 2 deletions oarepo_requests/translations/cs/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-03-27 11:31+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"PO-Revision-Date: 2024-06-19 14:40+0200\n"
"Last-Translator: \n"
"Language-Team: cs <[email protected]>\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n"
"Generated-By: Babel 2.14.0\n"
"X-Generator: Poedit 3.4.4\n"

#: oarepo_requests/services/ui_schema.py:71
msgid "status"
Expand Down Expand Up @@ -204,3 +205,18 @@ msgstr "Chyba při načítání žádostí"

msgid "Loading requests"
msgstr "Načítám žádosti"

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/delete_record.py:12
msgid "Delete record"
msgstr "Smazat záznam"

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/edit_record.py:13
msgid "Edit record"
msgstr "Upravit záznam"

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/publish_draft.py:12
msgid "Publish draft"
msgstr "Publikovat"

msgid "Close"
msgstr "Zavřít"
Binary file modified oarepo_requests/translations/en/LC_MESSAGES/messages.mo
Binary file not shown.
15 changes: 15 additions & 0 deletions oarepo_requests/translations/en/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -202,5 +202,20 @@ msgstr ""
msgid "Loading requests"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/delete_record.py:12
msgid "Delete record"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/edit_record.py:13
msgid "Edit record"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/publish_draft.py:12
msgid "Publish draft"
msgstr ""

msgid "Close"
msgstr ""

#~ msgid "No status"
#~ msgstr ""
Binary file modified oarepo_requests/translations/messages.mo
Binary file not shown.
39 changes: 27 additions & 12 deletions oarepo_requests/translations/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,40 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-04-08 13:55+0200\n"
"POT-Creation-Date: 2024-06-19 14:40+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.14.0\n"
"Generated-By: Babel 2.15.0\n"

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:92
#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:94
msgid "Submitted"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:93
#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:95
msgid "Expired"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:94
#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:96
msgid "Accepted"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:95
#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:97
msgid "Declined"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:96
#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:98
msgid "Cancelled"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:98
#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:100
msgid "Status"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:104
#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/invenio_patches.py:106
msgid "Type"
msgstr ""

Expand Down Expand Up @@ -169,15 +169,27 @@ msgstr ""
msgid "api.requests"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/delete_record.py:14
#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/delete_record.py:12
msgid "Delete record"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/delete_record.py:18
msgid "Request deletion of published record"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/edit_record.py:16
#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/edit_record.py:13
msgid "Edit record"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/edit_record.py:20
msgid "Request re-opening of published record"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/publish_draft.py:14
#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/publish_draft.py:12
msgid "Publish draft"
msgstr ""

#: /Users/miroslavbauer/Code/github.com/oarepo/oarepo-requests/oarepo_requests/types/publish_draft.py:18
msgid "Request publishing of a draft"
msgstr ""

Expand Down Expand Up @@ -207,3 +219,6 @@ msgstr ""

msgid "Cancel request"
msgstr ""

msgid "Close"
msgstr ""
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import axios from "axios";

import { RequestModalContent, CreateRequestModalContent } from ".";
import { REQUEST_TYPE } from "../utils/objects";
import { isDeepEmpty } from "../utils";
import { isDeepEmpty, mapPayloadUiToInitialValues } from "../utils";
import { useConfirmDialog } from "../utils/hooks";

/**
* @typedef {import("../types").Request} Request
Expand All @@ -21,38 +22,20 @@ import { isDeepEmpty } from "../utils";
* @typedef {import("semantic-ui-react").ConfirmProps} ConfirmProps
*/

const mapPayloadUiToInitialValues = (payloadUi) => {
const initialValues = { payload: {} };
payloadUi?.forEach(section => {
section.fields.forEach(field => {
initialValues.payload[field.field] = "";
});
});
return initialValues;
};

/** @param {{ request: Request, requestTypes: RequestType[], requestModalType: RequestTypeEnum, isEventModal: boolean, triggerButton: ReactElement, fetchNewRequests: () => void }} props */
export const RequestModal = ({ request, requestTypes, requestModalType, isEventModal = false, triggerButton, fetchNewRequests }) => {
const [modalOpen, setModalOpen] = useState(false);
const [error, setError] = useState(null);

/** @type {[ConfirmProps, (props: ConfirmProps) => void]} */
const [confirmDialogProps, setConfirmDialogProps] = useState({
open: false,
content: i18next.t("Are you sure?"),
cancelButton: i18next.t("Cancel"),
confirmButton: i18next.t("OK"),
onCancel: () => setConfirmDialogProps(props => ({ ...props, open: false })),
onConfirm: () => setConfirmDialogProps(props => ({ ...props, open: false }))
});

const errorMessageRef = useRef(null);

const formik = useFormik({
initialValues: !_isEmpty(request?.payload) ? { payload: request.payload } : (request?.payload_ui ? mapPayloadUiToInitialValues(request?.payload_ui) : {}),
onSubmit: () => {}
});

const { confirmDialogProps, confirmAction } = useConfirmDialog(formik, sendRequest, isEventModal);

useEffect(() => {
if (error) {
errorMessageRef.current?.scrollIntoView({ behavior: "smooth" });
Expand Down Expand Up @@ -121,59 +104,6 @@ export const RequestModal = ({ request, requestTypes, requestModalType, isEventM
return callApi(actionUrl, 'post', mappedData);
}

const confirmAction = (requestType, createAndSubmit = false) => {
/** @type {ConfirmProps} */
let newConfirmDialogProps = {
open: true,
onConfirm: () => {
setConfirmDialogProps(props => ({ ...props, open: false }));
sendRequest(requestType);
},
onCancel: () => {
setConfirmDialogProps(props => ({ ...props, open: false }));
formik.setSubmitting(false);
}
};

switch (requestType) {
case REQUEST_TYPE.CREATE:
newConfirmDialogProps.header = isEventModal ? i18next.t("Submit event") : i18next.t("Create request");
break;
case REQUEST_TYPE.SUBMIT:
newConfirmDialogProps.header = i18next.t("Submit request");
newConfirmDialogProps.confirmButton = i18next.t("OK");
break;
case REQUEST_TYPE.CANCEL:
newConfirmDialogProps.header = i18next.t("Cancel request");
newConfirmDialogProps.confirmButton = <Button negative>{i18next.t("Cancel request")}</Button>;
break;
case REQUEST_TYPE.ACCEPT:
newConfirmDialogProps.header = i18next.t("Accept request");
newConfirmDialogProps.confirmButton = <Button positive>{i18next.t("Accept")}</Button>;
break;
case REQUEST_TYPE.DECLINE:
newConfirmDialogProps.header = i18next.t("Decline request");
newConfirmDialogProps.confirmButton = <Button negative>{i18next.t("Decline")}</Button>;
break;
default:
break;
}

if (createAndSubmit) {
newConfirmDialogProps = {
...newConfirmDialogProps,
header: i18next.t("Create and submit request"),
confirmButton: <Button positive>{i18next.t("Create and submit")}</Button>,
onConfirm: () => {
setConfirmDialogProps(props => ({ ...props, open: false }));
sendRequest(REQUEST_TYPE.CREATE, createAndSubmit);
}
}
}

setConfirmDialogProps(props => ({ ...props, ...newConfirmDialogProps }));
}

const onClose = () => {
setModalOpen(false);
setError(null);
Expand All @@ -184,7 +114,7 @@ export const RequestModal = ({ request, requestTypes, requestModalType, isEventM
try {
await formik.submitForm();
if (submitButtonName === "create-and-submit-request") {
confirmAction(REQUEST_TYPE.SUBMIT, true);
!_isEmpty(requestType?.payload_ui) ? confirmAction(REQUEST_TYPE.SUBMIT, true) : sendRequest(REQUEST_TYPE.SUBMIT, true);
return;
}
if (requestModalType === REQUEST_TYPE.SUBMIT) {
Expand Down Expand Up @@ -250,10 +180,12 @@ export const RequestModal = ({ request, requestTypes, requestModalType, isEventM
<Icon name="trash alternate" />
{i18next.t("Cancel request")}
</Button>
<Button title={i18next.t("Save drafted request")} onClick={() => sendRequest(REQUEST_TYPE.SAVE)} color="grey" icon labelPosition="left" floated="right">
<Icon name="save" />
{i18next.t("Save")}
</Button>
{formWillBeRendered &&
<Button title={i18next.t("Save drafted request")} onClick={() => sendRequest(REQUEST_TYPE.SAVE)} color="grey" icon labelPosition="left" floated="right">
<Icon name="save" />
{i18next.t("Save")}
</Button>
}
</>
}
{requestModalType === REQUEST_TYPE.CANCEL &&
Expand All @@ -276,23 +208,25 @@ export const RequestModal = ({ request, requestTypes, requestModalType, isEventM
}
{requestModalType === REQUEST_TYPE.CREATE && (!isEventModal &&
<>
<Button type="submit" form="request-form" name="create-request" title={i18next.t("Create request")} color="blue" icon labelPosition="left" floated="right">
<Icon name="plus" />
{i18next.t("Create")}
</Button>
<Button type="submit" form="request-form" name="create-and-submit-request" title={i18next.t("Submit request")} color="blue" icon labelPosition="left" floated="left">
{requestType?.payload_ui &&
<Button type="submit" form="request-form" name="create-request" title={i18next.t("Create request")} color="blue" icon labelPosition="left" floated="right">
<Icon name="plus" />
{i18next.t("Create")}
</Button>
}
<Button type="submit" form="request-form" name="create-and-submit-request" title={i18next.t("Submit request")} color="blue" icon labelPosition="left" floated="right">
<Icon name="paper plane" />
{i18next.t("Submit")}
</Button>
</> ||
<Button type="submit" form="request-form" name="create-event" title={i18next.t("Submit")} color="blue" icon labelPosition="left" floated="left">
<Button type="submit" form="request-form" name="create-event" title={i18next.t("Submit")} color="blue" icon labelPosition="left" floated="right">
<Icon name="plus" />
{i18next.t("Submit")}
</Button>)
}
<Button onClick={onClose} icon labelPosition="left">
<Icon name="cancel" />
{i18next.t("Cancel")}
{i18next.t("Close")}
</Button>
</Modal.Actions>
<Confirm {...confirmDialogProps} />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { useState } from "react";

import { i18next } from "@translations/oarepo_requests_ui/i18next";
import { Button } from "semantic-ui-react";

import { REQUEST_TYPE } from "./objects";

/**
* @typedef {import("semantic-ui-react").ConfirmProps} ConfirmProps
*/

export const useConfirmDialog = (formik, sendRequest, isEventModal) => {
/** @type {[ConfirmProps, (props: ConfirmProps) => void]} */
const [confirmDialogProps, setConfirmDialogProps] = useState({
open: false,
content: i18next.t("Are you sure?"),
cancelButton: i18next.t("Close"),
confirmButton: i18next.t("OK"),
onCancel: () => setConfirmDialogProps(props => ({ ...props, open: false })),
onConfirm: () => setConfirmDialogProps(props => ({ ...props, open: false }))
});

const confirmAction = (requestType, createAndSubmit = false) => {
/** @type {ConfirmProps} */
let newConfirmDialogProps = {
open: true,
onConfirm: () => {
setConfirmDialogProps(props => ({ ...props, open: false }));
sendRequest(requestType);
},
onCancel: () => {
setConfirmDialogProps(props => ({ ...props, open: false }));
formik.setSubmitting(false);
}
};

switch (requestType) {
case REQUEST_TYPE.CREATE:
newConfirmDialogProps.header = isEventModal ? i18next.t("Submit event") : i18next.t("Create request");
break;
case REQUEST_TYPE.SUBMIT:
newConfirmDialogProps.header = i18next.t("Submit request");
newConfirmDialogProps.confirmButton = i18next.t("OK");
break;
case REQUEST_TYPE.CANCEL:
newConfirmDialogProps.header = i18next.t("Cancel request");
newConfirmDialogProps.confirmButton = <Button negative>{i18next.t("Cancel request")}</Button>;
break;
case REQUEST_TYPE.ACCEPT:
newConfirmDialogProps.header = i18next.t("Accept request");
newConfirmDialogProps.confirmButton = <Button positive>{i18next.t("Accept")}</Button>;
break;
case REQUEST_TYPE.DECLINE:
newConfirmDialogProps.header = i18next.t("Decline request");
newConfirmDialogProps.confirmButton = <Button negative>{i18next.t("Decline")}</Button>;
break;
default:
break;
}

if (createAndSubmit) {
newConfirmDialogProps = {
...newConfirmDialogProps,
header: i18next.t("Create and submit request"),
confirmButton: <Button positive>{i18next.t("Create and submit")}</Button>,
onConfirm: () => {
setConfirmDialogProps(props => ({ ...props, open: false }));
sendRequest(REQUEST_TYPE.CREATE, createAndSubmit);
}
}
}

setConfirmDialogProps(props => ({ ...props, ...newConfirmDialogProps }));
};

return { confirmDialogProps, confirmAction };
}
Loading

0 comments on commit 0ad0f2b

Please sign in to comment.