Skip to content
Snippets Groups Projects
Commit 0031b24f authored by xaralis's avatar xaralis
Browse files

feat: monitoring actions loading and notify users

parent 83317eb7
No related branches found
No related tags found
No related merge requests found
Pipeline #1856 passed
...@@ -142,6 +142,26 @@ export const hide = createAsyncAction( ...@@ -142,6 +142,26 @@ export const hide = createAsyncAction(
} }
); );
/**
* Edit post content.
*/
export const edit = createAsyncAction(
/**
* @param {CF2021.Post} post
*/
async ({ post, newContent }) => {
try {
const body = JSON.stringify({
content: newContent,
});
await fetch(`/posts/${post.id}`, { method: "PUT", body });
return successResult();
} catch (err) {
return errorResult([], err.toString());
}
}
);
/** /**
* *
* @param {CF2021.ProposalPost} proposal * @param {CF2021.ProposalPost} proposal
......
...@@ -10,6 +10,7 @@ const Button = ({ ...@@ -10,6 +10,7 @@ const Button = ({
iconChildren = null, iconChildren = null,
hoverActive = true, hoverActive = true,
fullwidth = false, fullwidth = false,
loading = false,
children, children,
routerTo, routerTo,
...props ...props
...@@ -21,6 +22,7 @@ const Button = ({ ...@@ -21,6 +22,7 @@ const Button = ({
"btn--icon": !!icon, "btn--icon": !!icon,
"btn--hoveractive": hoverActive, "btn--hoveractive": hoverActive,
"btn--fullwidth md:btn--autowidth": fullwidth, "btn--fullwidth md:btn--autowidth": fullwidth,
"btn--loading": loading,
}, },
className className
); );
......
import React from "react";
import classNames from "classnames";
const ErrorMessage = ({ className, children }) => {
return (
<div className={classNames("text-red-600 font-bold", className)}>
{children}
</div>
);
};
export default ErrorMessage;
...@@ -11,9 +11,9 @@ const AnnouncementList = ({ ...@@ -11,9 +11,9 @@ const AnnouncementList = ({
onEdit, onEdit,
onSeen, onSeen,
}) => { }) => {
const buildHandler = (responderFn) => (post) => (evt) => { const buildHandler = (responderFn) => (announcement) => (evt) => {
evt.preventDefault(); evt.preventDefault();
responderFn(post); responderFn(announcement);
}; };
const onAnnouncementEdit = buildHandler(onEdit); const onAnnouncementEdit = buildHandler(onEdit);
......
...@@ -18,6 +18,7 @@ const ModalConfirm = ({ ...@@ -18,6 +18,7 @@ const ModalConfirm = ({
cancelActionLabel = "Zrušit", cancelActionLabel = "Zrušit",
onCancel, onCancel,
onConfirm, onConfirm,
confirming,
...props ...props
}) => { }) => {
return ( return (
...@@ -38,6 +39,7 @@ const ModalConfirm = ({ ...@@ -38,6 +39,7 @@ const ModalConfirm = ({
color="blue-300" color="blue-300"
className="text-sm" className="text-sm"
onClick={onConfirm} onClick={onConfirm}
loading={confirming}
> >
{yesActionLabel} {yesActionLabel}
</Button> </Button>
......
...@@ -29,6 +29,7 @@ const Post = ({ ...@@ -29,6 +29,7 @@ const Post = ({
onAcceptProcedureProposal, onAcceptProcedureProposal,
onRejectProcedureProposal, onRejectProcedureProposal,
onRejectProcedureProposalByChairman, onRejectProcedureProposalByChairman,
onEdit,
onSeen, onSeen,
}) => { }) => {
const { ref, inView } = useInView({ const { ref, inView } = useInView({
...@@ -128,6 +129,7 @@ const Post = ({ ...@@ -128,6 +129,7 @@ const Post = ({
type === "procedure-proposal" && state === "announced"; type === "procedure-proposal" && state === "announced";
const showRejectByChairmanAction = const showRejectByChairmanAction =
type === "procedure-proposal" && ["announced", "pending"].includes(state); type === "procedure-proposal" && ["announced", "pending"].includes(state);
const showEditAction = true;
const showBanAction = true; const showBanAction = true;
const showHideAction = !archived; const showHideAction = !archived;
...@@ -199,6 +201,13 @@ const Post = ({ ...@@ -199,6 +201,13 @@ const Post = ({
title="Zamítnout procedurální návrh předsedajícím" title="Zamítnout procedurální návrh předsedajícím"
/> />
)} )}
{showEditAction && (
<DropdownMenuItem
onClick={onEdit}
icon="ico--edit-pencil"
title="Upravit příspěvek"
/>
)}
{showBanAction && ( {showBanAction && (
<DropdownMenuItem <DropdownMenuItem
onClick={onBanUser} onClick={onBanUser}
......
import React, { useState } from "react";
import Button from "components/Button";
import { Card, CardActions, CardBody, CardHeadline } from "components/cards";
import Modal from "components/modals/Modal";
const PostEditModal = ({ post, onCancel, onConfirm, ...props }) => {
const [text, setText] = useState(post.content);
const onTextInput = (evt) => {
setText(evt.target.value);
};
const confirm = (evt) => {
if (!!text) {
onConfirm(text);
}
};
return (
<Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}>
<Card>
<CardBody>
<div className="flex items-center justify-between mb-4">
<CardHeadline>Upravit text příspěvku</CardHeadline>
<button onClick={onCancel}>
<i className="ico--close"></i>
</button>
</div>
<div className="form-field">
<label className="form-field__label" htmlFor="field">
Nový text příspěvku
</label>
<div className="form-field__wrapper form-field__wrapper--shadowed">
<textarea
className="text-input form-field__control text-base"
value={text}
rows="8"
placeholder="Vyplňte text příspěvku"
onChange={onTextInput}
></textarea>
</div>
</div>
</CardBody>
<CardActions right className="space-x-1">
<Button
hoverActive
color="blue-300"
className="text-sm"
onClick={confirm}
>
Uložit
</Button>
<Button
hoverActive
color="red-600"
className="text-sm"
onClick={onCancel}
>
Zrušit
</Button>
</CardActions>
</Card>
</Modal>
);
};
export default PostEditModal;
...@@ -16,6 +16,7 @@ const PostList = ({ ...@@ -16,6 +16,7 @@ const PostList = ({
onAcceptProcedureProposal, onAcceptProcedureProposal,
onRejectProcedureProposal, onRejectProcedureProposal,
onRejectProcedureProposalByChairman, onRejectProcedureProposalByChairman,
onEdit,
onSeen, onSeen,
dimArchived, dimArchived,
}) => { }) => {
...@@ -26,6 +27,7 @@ const PostList = ({ ...@@ -26,6 +27,7 @@ const PostList = ({
const onPostLike = buildHandler(onLike); const onPostLike = buildHandler(onLike);
const onPostDislike = buildHandler(onDislike); const onPostDislike = buildHandler(onDislike);
const onPostEdit = buildHandler(onEdit);
const onPostHide = buildHandler(onHide); const onPostHide = buildHandler(onHide);
const onPostBanUser = buildHandler(onBanUser); const onPostBanUser = buildHandler(onBanUser);
const onPostAnnounceProcedureProposal = buildHandler( const onPostAnnounceProcedureProposal = buildHandler(
...@@ -71,11 +73,14 @@ const PostList = ({ ...@@ -71,11 +73,14 @@ const PostList = ({
onRejectProcedureProposalByChairman={onPostRejectProcedureProposalByChairman( onRejectProcedureProposalByChairman={onPostRejectProcedureProposalByChairman(
item item
)} )}
onEdit={onPostEdit(item)}
onSeen={onPostSeen(item)} onSeen={onPostSeen(item)}
/> />
))} ))}
{!items.length && ( {!items.length && (
<p>Nikdo zatím žádný příspěvek do rozpravy nepřidal. Budeš první?</p> <p className="p-4 lg:p-0 lg:py-3 ">
Nikdo zatím žádný příspěvek do rozpravy nepřidal. Budeš první?
</p>
)} )}
</div> </div>
); );
......
...@@ -3,6 +3,7 @@ import classNames from "classnames"; ...@@ -3,6 +3,7 @@ import classNames from "classnames";
import { addAnnouncement } from "actions/announcements"; import { addAnnouncement } from "actions/announcements";
import Button from "components/Button"; import Button from "components/Button";
import { useActionLoading } from "hooks";
const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/; const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
...@@ -12,6 +13,12 @@ const AddAnnouncementForm = ({ className }) => { ...@@ -12,6 +13,12 @@ const AddAnnouncementForm = ({ className }) => {
const [linkValid, setLinkValid] = useState(false); const [linkValid, setLinkValid] = useState(false);
const [type, setType] = useState("announcement"); const [type, setType] = useState("announcement");
const addingAnnouncement = useActionLoading(addAnnouncement, {
content: text,
link,
type,
});
const onTextInput = (evt) => { const onTextInput = (evt) => {
setText(evt.target.value); setText(evt.target.value);
}; };
...@@ -24,12 +31,15 @@ const AddAnnouncementForm = ({ className }) => { ...@@ -24,12 +31,15 @@ const AddAnnouncementForm = ({ className }) => {
} }
}; };
const onAdd = (evt) => { const onAdd = async (evt) => {
if (!!text) { if (!!text) {
addAnnouncement.run({ content: text, link, type }); const result = await addAnnouncement.run({ content: text, link, type });
if (!result.error) {
setText(""); setText("");
setLink(""); setLink("");
} }
}
}; };
return ( return (
...@@ -102,7 +112,10 @@ const AddAnnouncementForm = ({ className }) => { ...@@ -102,7 +112,10 @@ const AddAnnouncementForm = ({ className }) => {
onClick={onAdd} onClick={onAdd}
className="text-sm mt-4" className="text-sm mt-4"
hoverActive hoverActive
disabled={!text || (type === "voting" && !linkValid)} loading={addingAnnouncement}
disabled={
!text || (type === "voting" && !linkValid) || addingAnnouncement
}
> >
Přidat oznámení Přidat oznámení
</Button> </Button>
......
...@@ -2,28 +2,37 @@ import React, { useState } from "react"; ...@@ -2,28 +2,37 @@ import React, { useState } from "react";
import { addPost, addProposal } from "actions/posts"; import { addPost, addProposal } from "actions/posts";
import Button from "components/Button"; import Button from "components/Button";
import { useActionLoading } from "hooks";
const AddPostForm = ({ className }) => { const AddPostForm = ({ className }) => {
const [text, setText] = useState(""); const [text, setText] = useState("");
const addingPost = useActionLoading(addPost, { content: text });
const addingProposal = useActionLoading(addPost, { content: text });
const onTextInput = (evt) => { const onTextInput = (evt) => {
setText(evt.target.value); setText(evt.target.value);
}; };
const onAddPost = (evt) => { const onAddPost = async (evt) => {
if (!!text) { if (!!text) {
addPost.run({ content: text }); const result = await addPost.run({ content: text });
if (!result.error) {
setText(""); setText("");
} }
}
}; };
const onAddProposal = (evt) => { const onAddProposal = async (evt) => {
evt.stopPropagation(); evt.stopPropagation();
if (!!text) { if (!!text) {
addProposal.run({ content: text }); const result = await addProposal.run({ content: text });
if (!result.error) {
setText(""); setText("");
} }
}
}; };
const buttonDropdownActionList = ( const buttonDropdownActionList = (
...@@ -54,7 +63,8 @@ const AddPostForm = ({ className }) => { ...@@ -54,7 +63,8 @@ const AddPostForm = ({ className }) => {
<div className="space-x-4"> <div className="space-x-4">
<Button <Button
onClick={onAddPost} onClick={onAddPost}
disabled={!text} disabled={!text || addingPost || addingProposal}
loading={addingPost || addingProposal}
hoverActive hoverActive
icon="ico--chevron-down" icon="ico--chevron-down"
iconWrapperClassName="dropdown-button" iconWrapperClassName="dropdown-button"
......
...@@ -2,16 +2,20 @@ import React, { useCallback, useState } from "react"; ...@@ -2,16 +2,20 @@ import React, { useCallback, useState } from "react";
import { import {
deleteAnnouncement, deleteAnnouncement,
loadAnnouncements,
updateAnnouncementContent, updateAnnouncementContent,
} from "actions/announcements"; } from "actions/announcements";
import AnnouncementEditModal from "components/annoucements/AnnouncementEditModal"; import AnnouncementEditModal from "components/annoucements/AnnouncementEditModal";
import AnnouncementList from "components/annoucements/AnnouncementList"; import AnnouncementList from "components/annoucements/AnnouncementList";
import { CardBody } from "components/cards";
import ErrorMessage from "components/ErrorMessage";
import ModalConfirm from "components/modals/ModalConfirm"; import ModalConfirm from "components/modals/ModalConfirm";
import { useItemActionConfirm } from "hooks"; import { useActionLoading, useItemActionConfirm } from "hooks";
import { AnnouncementStore, AuthStore } from "stores"; import { AnnouncementStore, AuthStore } from "stores";
const AnnoucementsContainer = () => { const AnnoucementsContainer = () => {
const [itemToEdit, setItemToEdit] = useState(null); const [itemToEdit, setItemToEdit] = useState(null);
const { 2: loadResult } = loadAnnouncements.useWatch();
const [ const [
itemToDelete, itemToDelete,
...@@ -20,6 +24,11 @@ const AnnoucementsContainer = () => { ...@@ -20,6 +24,11 @@ const AnnoucementsContainer = () => {
onDeleteCancel, onDeleteCancel,
] = useItemActionConfirm(deleteAnnouncement); ] = useItemActionConfirm(deleteAnnouncement);
const deletingAnnouncement = useActionLoading(
deleteAnnouncement,
itemToDelete
);
const { isAuthenticated, user } = AuthStore.useState(); const { isAuthenticated, user } = AuthStore.useState();
const items = AnnouncementStore.useState((state) => const items = AnnouncementStore.useState((state) =>
state.itemIds.map((id) => state.items[id]) state.itemIds.map((id) => state.items[id])
...@@ -51,6 +60,13 @@ const AnnoucementsContainer = () => { ...@@ -51,6 +60,13 @@ const AnnoucementsContainer = () => {
return ( return (
<> <>
{loadResult && loadResult.error && (
<CardBody>
<ErrorMessage>
Oznámení se nepodařilo načíst: {loadResult.message}
</ErrorMessage>
</CardBody>
)}
<AnnouncementList <AnnouncementList
items={items} items={items}
canRunActions={isAuthenticated && user.role === "chairman"} canRunActions={isAuthenticated && user.role === "chairman"}
...@@ -62,6 +78,7 @@ const AnnoucementsContainer = () => { ...@@ -62,6 +78,7 @@ const AnnoucementsContainer = () => {
isOpen={!!itemToDelete} isOpen={!!itemToDelete}
onConfirm={onDeleteConfirm} onConfirm={onDeleteConfirm}
onCancel={onDeleteCancel} onCancel={onDeleteCancel}
confirming={deletingAnnouncement}
title="Opravdu smazat?" title="Opravdu smazat?"
yesActionLabel="Smazat" yesActionLabel="Smazat"
> >
......
import React from "react"; import React, { useCallback, useState } from "react";
import pick from "lodash/pick"; import pick from "lodash/pick";
import { import {
acceptProposal, acceptProposal,
announceProposal, announceProposal,
dislike, dislike,
edit,
hide, hide,
like, like,
loadPosts,
rejectProposal, rejectProposal,
rejectProposalByChairman, rejectProposalByChairman,
} from "actions/posts"; } from "actions/posts";
import { ban } from "actions/users"; import { ban } from "actions/users";
import ErrorMessage from "components/ErrorMessage";
import ModalConfirm from "components/modals/ModalConfirm"; import ModalConfirm from "components/modals/ModalConfirm";
import PostEditModal from "components/posts/PostEditModal";
import PostList from "components/posts/PostList"; import PostList from "components/posts/PostList";
import { useItemActionConfirm } from "hooks"; import { useActionLoading, useItemActionConfirm } from "hooks";
import { AuthStore, PostStore } from "stores"; import { AuthStore, PostStore } from "stores";
const PostsContainer = ({ className }) => { const PostsContainer = ({ className }) => {
const [postToEdit, setPostToEdit] = useState(null);
const [ const [
userToBan, userToBan,
setUserToBan, setUserToBan,
...@@ -62,6 +68,32 @@ const PostsContainer = ({ className }) => { ...@@ -62,6 +68,32 @@ const PostsContainer = ({ className }) => {
(state) => state.filters.flags === "archived" (state) => state.filters.flags === "archived"
); );
const banningUser = useActionLoading(ban, userToBan);
const hidingPost = useActionLoading(hide, postToHide);
const announcingProposal = useActionLoading(announceProposal, postToAnnounce);
const acceptingProposal = useActionLoading(acceptProposal, postToAccept);
const rejectingProposal = useActionLoading(rejectProposal, postToReject);
const rejectingProposalByChairman = useActionLoading(
rejectProposalByChairman,
postToRejectByChairman
);
const { 2: loadResult } = loadPosts.useWatch();
const confirmEdit = useCallback(
async (newContent) => {
if (postToEdit && newContent) {
await edit.run({ post: postToEdit, newContent });
setPostToEdit(null);
}
},
[postToEdit, setPostToEdit]
);
const cancelEdit = useCallback(() => {
setPostToEdit(null);
}, [setPostToEdit]);
/** /**
* Ban a post's author. * Ban a post's author.
* @param {CF2021.Post} post * @param {CF2021.Post} post
...@@ -85,6 +117,11 @@ const PostsContainer = ({ className }) => { ...@@ -85,6 +117,11 @@ const PostsContainer = ({ className }) => {
return ( return (
<> <>
{loadResult && loadResult.error && (
<ErrorMessage>
Příspěvky se nepodařilo načíst: {loadResult.message}
</ErrorMessage>
)}
<PostList <PostList
items={window.items items={window.items
.slice(sliceStart, sliceEnd) .slice(sliceStart, sliceEnd)
...@@ -98,6 +135,7 @@ const PostsContainer = ({ className }) => { ...@@ -98,6 +135,7 @@ const PostsContainer = ({ className }) => {
dimArchived={!showingArchivedOnly} dimArchived={!showingArchivedOnly}
onHide={setPostToHide} onHide={setPostToHide}
onBanUser={onBanUser} onBanUser={onBanUser}
onEdit={setPostToEdit}
onAnnounceProcedureProposal={setPostToAnnounce} onAnnounceProcedureProposal={setPostToAnnounce}
onAcceptProcedureProposal={setPostToAccept} onAcceptProcedureProposal={setPostToAccept}
onRejectProcedureProposal={setPostToReject} onRejectProcedureProposal={setPostToReject}
...@@ -107,6 +145,7 @@ const PostsContainer = ({ className }) => { ...@@ -107,6 +145,7 @@ const PostsContainer = ({ className }) => {
isOpen={!!userToBan} isOpen={!!userToBan}
onConfirm={onBanUserConfirm} onConfirm={onBanUserConfirm}
onCancel={onBanUserCancel} onCancel={onBanUserCancel}
confirming={banningUser}
title={`Zablokovat uživatele ${userToBan ? userToBan.name : null}?`} title={`Zablokovat uživatele ${userToBan ? userToBan.name : null}?`}
yesActionLabel="Zablokovat" yesActionLabel="Zablokovat"
> >
...@@ -117,15 +156,7 @@ const PostsContainer = ({ className }) => { ...@@ -117,15 +156,7 @@ const PostsContainer = ({ className }) => {
isOpen={!!postToHide} isOpen={!!postToHide}
onConfirm={onPostHideConfirm} onConfirm={onPostHideConfirm}
onCancel={onPostHideCancel} onCancel={onPostHideCancel}
title="Skrýt příspěvek?" confirming={hidingPost}
yesActionLabel="Potvrdit"
>
Příspěvek se skryje a uživatelé ho neuvidí. Opravdu to chcete?
</ModalConfirm>
<ModalConfirm
isOpen={!!postToHide}
onConfirm={onPostHideConfirm}
onCancel={onPostHideCancel}
title="Skrýt příspěvek?" title="Skrýt příspěvek?"
yesActionLabel="Potvrdit" yesActionLabel="Potvrdit"
> >
...@@ -135,6 +166,7 @@ const PostsContainer = ({ className }) => { ...@@ -135,6 +166,7 @@ const PostsContainer = ({ className }) => {
isOpen={!!postToAnnounce} isOpen={!!postToAnnounce}
onConfirm={onAnnounceConfirm} onConfirm={onAnnounceConfirm}
onCancel={onAnnounceCancel} onCancel={onAnnounceCancel}
confirming={announcingProposal}
title="Vyhlásit procedurální návrh?" title="Vyhlásit procedurální návrh?"
yesActionLabel="Vyhlásit návrh" yesActionLabel="Vyhlásit návrh"
> >
...@@ -144,6 +176,7 @@ const PostsContainer = ({ className }) => { ...@@ -144,6 +176,7 @@ const PostsContainer = ({ className }) => {
isOpen={!!postToAccept} isOpen={!!postToAccept}
onConfirm={onAcceptConfirm} onConfirm={onAcceptConfirm}
onCancel={onAcceptCancel} onCancel={onAcceptCancel}
confirming={acceptingProposal}
title="Schválit procedurální návrh?" title="Schválit procedurální návrh?"
yesActionLabel="Schválit návrh" yesActionLabel="Schválit návrh"
> >
...@@ -153,6 +186,7 @@ const PostsContainer = ({ className }) => { ...@@ -153,6 +186,7 @@ const PostsContainer = ({ className }) => {
isOpen={!!postToReject} isOpen={!!postToReject}
onConfirm={onRejectConfirm} onConfirm={onRejectConfirm}
onCancel={onRejectCancel} onCancel={onRejectCancel}
confirming={rejectingProposal}
title="Zamítnout procedurální návrh?" title="Zamítnout procedurální návrh?"
yesActionLabel="Zamítnout návrh" yesActionLabel="Zamítnout návrh"
> >
...@@ -162,12 +196,21 @@ const PostsContainer = ({ className }) => { ...@@ -162,12 +196,21 @@ const PostsContainer = ({ className }) => {
isOpen={!!postToRejectByChairman} isOpen={!!postToRejectByChairman}
onConfirm={onRejectByChairmanConfirm} onConfirm={onRejectByChairmanConfirm}
onCancel={onRejectByChairmanCancel} onCancel={onRejectByChairmanCancel}
confirming={rejectingProposalByChairman}
title="Zamítnout procedurální návrh předsedajícícm?" title="Zamítnout procedurální návrh předsedajícícm?"
yesActionLabel="Zamítnout návrh předsedajícím" yesActionLabel="Zamítnout návrh předsedajícím"
> >
Procedurální návrh bude <strong>zamítnut předsedajícím</strong>. Opravdu Procedurální návrh bude <strong>zamítnut předsedajícím</strong>. Opravdu
to chcete? to chcete?
</ModalConfirm> </ModalConfirm>
{postToEdit && (
<PostEditModal
isOpen={true}
post={postToEdit}
onConfirm={confirmEdit}
onCancel={cancelEdit}
/>
)}
</> </>
); );
}; };
......
...@@ -3,11 +3,14 @@ import { useCallback, useState } from "react"; ...@@ -3,11 +3,14 @@ import { useCallback, useState } from "react";
export const useItemActionConfirm = (actionFn) => { export const useItemActionConfirm = (actionFn) => {
const [item, setItem] = useState(null); const [item, setItem] = useState(null);
const onActionConfirm = useCallback(() => { const onActionConfirm = useCallback(async () => {
if (item) { if (item) {
actionFn.run(item); const result = await actionFn.run(item);
if (!result.error) {
setItem(null); setItem(null);
} }
}
}, [item, setItem, actionFn]); }, [item, setItem, actionFn]);
const onActionCancel = useCallback(() => { const onActionCancel = useCallback(() => {
...@@ -20,11 +23,14 @@ export const useItemActionConfirm = (actionFn) => { ...@@ -20,11 +23,14 @@ export const useItemActionConfirm = (actionFn) => {
export const useActionConfirm = (actionFn, actionArgs) => { export const useActionConfirm = (actionFn, actionArgs) => {
const [showConfirm, setShowConfirm] = useState(false); const [showConfirm, setShowConfirm] = useState(false);
const onActionConfirm = useCallback(() => { const onActionConfirm = useCallback(async () => {
if (showConfirm) { if (showConfirm) {
actionFn.run(actionArgs); const result = await actionFn.run(actionArgs);
if (!result.error) {
setShowConfirm(false); setShowConfirm(false);
} }
}
}, [showConfirm, setShowConfirm, actionFn, actionArgs]); }, [showConfirm, setShowConfirm, actionFn, actionArgs]);
const onActionCancel = useCallback(() => { const onActionCancel = useCallback(() => {
...@@ -33,3 +39,8 @@ export const useActionConfirm = (actionFn, actionArgs) => { ...@@ -33,3 +39,8 @@ export const useActionConfirm = (actionFn, actionArgs) => {
return [showConfirm, setShowConfirm, onActionConfirm, onActionCancel]; return [showConfirm, setShowConfirm, onActionConfirm, onActionCancel];
}; };
export const useActionLoading = (actionFn, actionArgs) => {
const { 0: started, 1: finished } = actionFn.useWatch(actionArgs);
return started && !finished;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment