Skip to content
Snippets Groups Projects
Commit 26fbc88c authored by xaralis's avatar xaralis
Browse files

feat: edit announcement (wip)

parent c2fe36f7
No related branches found
No related tags found
No related merge requests found
Pipeline #1822 failed
...@@ -10949,19 +10949,12 @@ ...@@ -10949,19 +10949,12 @@
} }
}, },
"pullstate": { "pullstate": {
"version": "1.20.4", "version": "1.20.5",
"resolved": "https://registry.npmjs.org/pullstate/-/pullstate-1.20.4.tgz", "resolved": "https://registry.npmjs.org/pullstate/-/pullstate-1.20.5.tgz",
"integrity": "sha512-SksJ70iYNrC+YsGjMx54pXT2/iYYUu3zg9hezjHNjPPwyViglo4lh+N0I4DwB6xw92s+9NagD3AXMGMfiIt76g==", "integrity": "sha512-9+QAXjf5WugIPEFHgMTwKM42uDx8ezB1BDobh7gpg9OCta5rp1XdFxa6tLljB/4NUxnI5YqoiE2s15ZOh+sl4A==",
"requires": { "requires": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"immer": "^7.0.1" "immer": "^7.0.1"
},
"dependencies": {
"immer": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/immer/-/immer-7.0.15.tgz",
"integrity": "sha512-yM7jo9+hvYgvdCQdqvhCNRRio0SCXc8xDPzA25SvKWa7b1WVPjLwQs1VYU5JPXjcJPTqAa5NP5dqpORGYBQ2AA=="
}
} }
}, },
"pump": { "pump": {
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
"immer": "^7.0.15", "immer": "^7.0.15",
"keycloak-js": "^10.0.2", "keycloak-js": "^10.0.2",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"pullstate": "^1.20.4", "pullstate": "^1.20.5",
"react": "^16.13.1", "react": "^16.13.1",
"react-device-detect": "^1.13.1", "react-device-detect": "^1.13.1",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
......
import findIndex from "lodash/findIndex";
import remove from "lodash/remove";
import { createAsyncAction, successResult } from "pullstate"; import { createAsyncAction, successResult } from "pullstate";
import { AnnouncementStore } from "stores"; import { AnnouncementStore } from "stores";
...@@ -20,9 +22,59 @@ export const addAnnouncement = createAsyncAction( ...@@ -20,9 +22,59 @@ export const addAnnouncement = createAsyncAction(
}, },
{ {
postActionHook: ({ result }) => { postActionHook: ({ result }) => {
if (!result.error) {
AnnouncementStore.update((state) => { AnnouncementStore.update((state) => {
state.items.push(result.payload); state.items.push(result.payload);
}); });
}
},
}
);
/**
* Delete existing announcement.
*/
export const deleteAnnouncement = createAsyncAction(
/**
*
* @param {CF2021.Announcement} item
*/
async (item) => {
return successResult(item);
},
{
postActionHook: ({ result }) => {
if (!result.error) {
AnnouncementStore.update((state) => {
remove(state.items, { id: result.payload.id });
});
}
},
}
);
/**
* Update content of an announcement.
*/
export const updateAnnouncementContent = createAsyncAction(
/**
*
* @param {CF2021.Announcement} item
* @param {string} newContent
*/
async (item, newContent) => {
return successResult({ item, newContent });
},
{
postActionHook: ({ result }) => {
if (!result.error) {
AnnouncementStore.update((state) => {
const itemIdx = findIndex(state.items, {
id: result.payload.item.id,
});
state.items[itemIdx].content = result.payload.newContent;
});
}
}, },
} }
); );
import { fetch } from "api";
import pick from "lodash/pick"; import pick from "lodash/pick";
import { createAsyncAction, errorResult, successResult } from "pullstate"; import { createAsyncAction, errorResult, successResult } from "pullstate";
import fetch from "unfetch";
import { ProgramStore } from "stores"; import { ProgramStore } from "stores";
export const loadProgram = createAsyncAction( export const loadProgram = createAsyncAction(
async () => { async () => {
try { try {
const resp = await fetch(`${process.env.REACT_APP_API_BASE_URL}/program`); const resp = await fetch("/program");
const mappings = await resp.json(); const mappings = await resp.json();
return successResult(mappings); return successResult(mappings);
} catch (err) { } catch (err) {
......
import baseFetch from "unfetch";
import { AuthStore } from "./stores";
export const fetch = (url, opts) => {
const { isAuthenticated, user } = AuthStore.getRawState();
opts = opts || {};
opts.headers = opts.headers || {};
if (isAuthenticated) {
// opts.headers.Authorization = "Bearer " + user.accessToken;
}
return baseFetch(process.env.REACT_APP_API_BASE_URL + url, opts);
};
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 AnnouncementEditModal = ({
announcement,
onCancel,
onConfirm,
...props
}) => {
const [text, setText] = useState(announcement.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 oznámení</CardHeadline>
<button onClick={onCancel}>
<i className="ico--close"></i>
</button>
</div>
<div className="form-field">
<div className="form-field__wrapper form-field__wrapper--shadowed">
<textarea
className="text-input form-field__control "
value={text}
rows="8"
placeholder="Vyplňte text oznámení"
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 AnnouncementEditModal;
import React from "react";
import classNames from "classnames";
const Card = ({ children, elevation = 21, className }) => {
const cls = classNames("card", `elevation-${elevation}`, className);
return <div className={cls}>{children}</div>;
};
export default Card;
import React from "react";
import classNames from "classnames";
const CardActions = ({ children, right, className }) => {
const cls = classNames(
"card-actions",
{ "card-actions--right": !!right },
className
);
return <div className={cls}>{children}</div>;
};
export default CardActions;
import React from "react";
import classNames from "classnames";
const CardBody = ({ children, className }) => {
const cls = classNames("card__body", className);
return <div className={cls}>{children}</div>;
};
export default CardBody;
import React from "react";
const CardBodyText = ({ children }) => {
return <div className="card-body-text">{children}</div>;
};
export default CardBodyText;
import React from "react";
const CardHeadline = ({ children }) => {
return <h1 className="card-headline">{children}</h1>;
};
export default CardHeadline;
export { default as Card } from "./Card";
export { default as CardActions } from "./CardActions";
export { default as CardBody } from "./CardBody";
export { default as CardBodyText } from "./CardBodyText";
export { default as CardHeadline } from "./CardHeadline";
import React from "react"; import React from "react";
import Button from "components/Button"; import Button from "components/Button";
import {
Card,
CardActions,
CardBody,
CardBodyText,
CardHeadline,
} from "components/cards";
import Modal from "./Modal"; import Modal from "./Modal";
...@@ -15,19 +22,19 @@ const ModalConfirm = ({ ...@@ -15,19 +22,19 @@ const ModalConfirm = ({
}) => { }) => {
return ( return (
<Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}> <Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}>
<div className="card elevation-21"> <Card>
<div className="card__body"> <CardBody>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h1 className="card-headline">{title}</h1> <CardHeadline>{title}</CardHeadline>
<button onClick={onCancel}> <button onClick={onCancel}>
<i className="ico--close"></i> <i className="ico--close"></i>
</button> </button>
</div> </div>
<p className="card-body-text">{children}</p> <CardBodyText>{children}</CardBodyText>
</div> </CardBody>
<div className="card-actions card-actions--right space-x-1"> <CardActions right className="space-x-1">
<Button <Button
hoveractive hoverActive
color="blue-300" color="blue-300"
className="text-sm" className="text-sm"
onClick={onConfirm} onClick={onConfirm}
...@@ -35,15 +42,15 @@ const ModalConfirm = ({ ...@@ -35,15 +42,15 @@ const ModalConfirm = ({
{yesActionLabel} {yesActionLabel}
</Button> </Button>
<Button <Button
hoveractive hoverActive
color="red-600" color="red-600"
className="text-sm" className="text-sm"
onClick={onConfirm} onClick={onCancel}
> >
{cancelActionLabel} {cancelActionLabel}
</Button> </Button>
</div> </CardActions>
</div> </Card>
</Modal> </Modal>
); );
}; };
......
import React from "react"; import React, { useCallback, useState } from "react";
import {
deleteAnnouncement,
updateAnnouncementContent,
} from "actions/announcements";
import AnnouncementEditModal from "components/annoucements/AnnouncementEditModal";
import AnnouncementList from "components/annoucements/AnnouncementList"; import AnnouncementList from "components/annoucements/AnnouncementList";
import ModalConfirm from "components/modals/ModalConfirm";
import { AnnouncementStore } from "stores"; import { AnnouncementStore } from "stores";
const AnnoucementsContainer = () => { const AnnoucementsContainer = () => {
const [itemToDelete, setItemToDelete] = useState(null);
const [itemToEdit, setItemToEdit] = useState(null);
const items = AnnouncementStore.useState((state) => state.items); const items = AnnouncementStore.useState((state) => state.items);
const onEdit = (announcement) => { const confirmEdit = useCallback(
console.log("edit", announcement); async (newContent) => {
}; if (itemToEdit && newContent) {
const onDelete = (announcement) => { await updateAnnouncementContent.run(itemToEdit, newContent);
console.log("delete", announcement); setItemToEdit(null);
}; }
},
[itemToEdit, setItemToEdit]
);
const cancelEdit = useCallback(() => {
setItemToEdit(null);
}, [setItemToEdit]);
const confirmDelete = useCallback(async () => {
await deleteAnnouncement.run(itemToDelete);
setItemToDelete(null);
}, [setItemToDelete, itemToDelete]);
const cancelDelete = useCallback(() => {
setItemToDelete(null);
}, [setItemToDelete]);
return ( return (
<>
<AnnouncementList <AnnouncementList
items={items} items={items}
displayActions={true} displayActions={true}
onDelete={onDelete} onDelete={setItemToDelete}
onEdit={onEdit} onEdit={setItemToEdit}
/>
<ModalConfirm
isOpen={!!itemToDelete}
onConfirm={confirmDelete}
onCancel={cancelDelete}
title="Opravdu chcete toto oznámení smazat?"
yesActionLabel="Smazat"
>
Opravdu chcete ukončit rozpravu?
</ModalConfirm>
{itemToEdit && (
<AnnouncementEditModal
isOpen={true}
announcement={itemToEdit}
onConfirm={confirmEdit}
onCancel={cancelEdit}
/> />
)}
</>
); );
}; };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment