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

feat: improve UX for add post form

parent ab0abb90
No related branches found
No related tags found
No related merge requests found
...@@ -1426,6 +1426,16 @@ ...@@ -1426,6 +1426,16 @@
"resolved": "https://registry.npmjs.org/@rooks/use-interval/-/use-interval-4.5.0.tgz", "resolved": "https://registry.npmjs.org/@rooks/use-interval/-/use-interval-4.5.0.tgz",
"integrity": "sha512-As0DueIAGLJLYATKPPOCDGqoIlwbhPAcYP14TNTHaAj9/ODdvUYFXAP3jFCRzDNpjXCIgSe4oBuzVVmM526n+Q==" "integrity": "sha512-As0DueIAGLJLYATKPPOCDGqoIlwbhPAcYP14TNTHaAj9/ODdvUYFXAP3jFCRzDNpjXCIgSe4oBuzVVmM526n+Q=="
}, },
"@rooks/use-outside-click": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rooks/use-outside-click/-/use-outside-click-4.5.0.tgz",
"integrity": "sha512-oNFSSVdGQUPq6W0K5YyCSfVEFRjrxkBoxW8k46SHu9m80XhHy+C9nOU+DGA9YGR55LIPtC7aVU08KDe4Uargug=="
},
"@rooks/use-timeout": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rooks/use-timeout/-/use-timeout-4.5.0.tgz",
"integrity": "sha512-g42L/gYLkC+E1bTX1sMOs8QTOjIwWDmCjASWZPRC0uM1iUWiQ8IrzyjB4m+AQXxLysWAcrq/eX605KkWNnrWhA=="
},
"@rooks/use-window-size": { "@rooks/use-window-size": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rooks/use-window-size/-/use-window-size-4.5.0.tgz", "resolved": "https://registry.npmjs.org/@rooks/use-window-size/-/use-window-size-4.5.0.tgz",
......
...@@ -78,7 +78,7 @@ const AnnouncementEditModal = ({ ...@@ -78,7 +78,7 @@ const AnnouncementEditModal = ({
return ( return (
<Modal containerClassName="max-w-lg" onRequestClose={onCancel} {...props}> <Modal containerClassName="max-w-lg" onRequestClose={onCancel} {...props}>
<form onSubmit={confirm}> <form onSubmit={confirm}>
<Card> <Card className="elevation-21">
<CardBody> <CardBody>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<CardHeadline>Upravit oznámení</CardHeadline> <CardHeadline>Upravit oznámení</CardHeadline>
......
import React from "react"; import React from "react";
import classNames from "classnames"; import classNames from "classnames";
const Card = ({ children, elevation = 21, className }) => { const Card = ({ children, className }, ref) => {
const cls = classNames("card", `elevation-${elevation}`, className); const cls = classNames("card", className);
return <div className={cls}>{children}</div>; return (
<div className={cls} ref={ref}>
{children}
</div>
);
}; };
export default Card; export default React.forwardRef(Card);
import React from "react"; import React from "react";
import classNames from "classnames"; import classNames from "classnames";
const CardBody = ({ children, className }) => { const CardBody = ({ children, className, ...props }) => {
const cls = classNames("card__body", className); const cls = classNames("card__body", className);
return <div className={cls}>{children}</div>; return (
<div className={cls} {...props}>
{children}
</div>
);
}; };
export default CardBody; export default CardBody;
...@@ -7,13 +7,10 @@ import { markdownConverter } from "markdown"; ...@@ -7,13 +7,10 @@ import { markdownConverter } from "markdown";
import "react-mde/lib/styles/css/react-mde-toolbar.css"; import "react-mde/lib/styles/css/react-mde-toolbar.css";
import "./MarkdownEditor.css"; import "./MarkdownEditor.css";
const MarkdownEditor = ({ const MarkdownEditor = (
value, { value, onChange, error, placeholder = "", ...props },
onChange, ref
error, ) => {
placeholder = "",
...props
}) => {
const [selectedTab, setSelectedTab] = useState("write"); const [selectedTab, setSelectedTab] = useState("write");
const classes = { const classes = {
...@@ -36,6 +33,7 @@ const MarkdownEditor = ({ ...@@ -36,6 +33,7 @@ const MarkdownEditor = ({
return ( return (
<div className={classNames("form-field", { "form-field--error": !!error })}> <div className={classNames("form-field", { "form-field--error": !!error })}>
<ReactMde <ReactMde
ref={ref}
value={value} value={value}
onChange={onChange} onChange={onChange}
selectedTab={selectedTab} selectedTab={selectedTab}
...@@ -53,4 +51,4 @@ const MarkdownEditor = ({ ...@@ -53,4 +51,4 @@ const MarkdownEditor = ({
); );
}; };
export default MarkdownEditor; export default React.forwardRef(MarkdownEditor);
...@@ -21,7 +21,7 @@ const ModalConfirm = ({ ...@@ -21,7 +21,7 @@ const ModalConfirm = ({
}) => { }) => {
return ( return (
<Modal onRequestClose={onClose} {...props}> <Modal onRequestClose={onClose} {...props}>
<Card> <Card className="elevation-21">
<CardBody> <CardBody>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<CardHeadline>{title}</CardHeadline> <CardHeadline>{title}</CardHeadline>
......
...@@ -42,7 +42,7 @@ const PostEditModal = ({ ...@@ -42,7 +42,7 @@ const PostEditModal = ({
return ( return (
<Modal containerClassName="max-w-xl" onRequestClose={onCancel} {...props}> <Modal containerClassName="max-w-xl" onRequestClose={onCancel} {...props}>
<form onSubmit={confirm}> <form onSubmit={confirm}>
<Card> <Card className="elevation-21">
<CardBody> <CardBody>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<CardHeadline>Upravit text příspěvku</CardHeadline> <CardHeadline>Upravit text příspěvku</CardHeadline>
......
...@@ -27,7 +27,7 @@ const RejectPostModalConfirm = ({ ...@@ -27,7 +27,7 @@ const RejectPostModalConfirm = ({
}) => { }) => {
return ( return (
<Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}> <Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}>
<Card> <Card className="elevation-21">
<CardBody> <CardBody>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<CardHeadline>{title}</CardHeadline> <CardHeadline>{title}</CardHeadline>
......
...@@ -24,7 +24,7 @@ const ProgramEntryEditModal = ({ ...@@ -24,7 +24,7 @@ const ProgramEntryEditModal = ({
return ( return (
<Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}> <Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}>
<Card> <Card className="elevation-21">
<CardBody> <CardBody>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<CardHeadline>Upravit název programového bodu</CardHeadline> <CardHeadline>Upravit název programového bodu</CardHeadline>
......
import React, { useState } from "react"; import React, { useCallback, useRef, useState } from "react";
import useOutsideClick from "@rooks/use-outside-click";
import useTimeout from "@rooks/use-timeout";
import classNames from "classnames";
import { addPost, addProposal } from "actions/posts"; import { addPost, addProposal } from "actions/posts";
import Button from "components/Button"; import Button from "components/Button";
import { Card, CardBody } from "components/cards";
import ErrorMessage from "components/ErrorMessage"; import ErrorMessage from "components/ErrorMessage";
import MarkdownEditor from "components/mde/MarkdownEditor"; import MarkdownEditor from "components/mde/MarkdownEditor";
import { useActionState } from "hooks"; import { useActionState } from "hooks";
const AddPostForm = ({ className }) => { const AddPostForm = ({ className }) => {
const cardRef = useRef();
const editorRef = useRef();
const [expanded, setExpanded] = useState(false);
const [text, setText] = useState(""); const [text, setText] = useState("");
const [showAddConfirm, setShowAddConfirm] = useState(false);
const [type, setType] = useState("post"); const [type, setType] = useState("post");
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [addingPost, addingPostError] = useActionState(addPost, { const [addingPost, addingPostError] = useActionState(addPost, {
...@@ -17,6 +25,29 @@ const AddPostForm = ({ className }) => { ...@@ -17,6 +25,29 @@ const AddPostForm = ({ className }) => {
content: text, content: text,
}); });
const onOutsideClick = useCallback(() => {
setExpanded(false);
}, [setExpanded]);
const onWrite = useCallback(() => {
if (!expanded) {
setExpanded(true);
setTimeout(() => {
if (editorRef.current && editorRef.current.finalRefs.textarea.current) {
editorRef.current.finalRefs.textarea.current.focus();
}
}, 0);
}
}, [setExpanded, expanded]);
const hideAddConfirm = useCallback(() => {
setShowAddConfirm(false);
}, [setShowAddConfirm]);
useOutsideClick(cardRef, onOutsideClick);
const { start: enqueueHideAddConfirm } = useTimeout(hideAddConfirm, 2000);
const onTextInput = (newText) => { const onTextInput = (newText) => {
setText(newText); setText(newText);
...@@ -38,6 +69,9 @@ const AddPostForm = ({ className }) => { ...@@ -38,6 +69,9 @@ const AddPostForm = ({ className }) => {
if (!result.error) { if (!result.error) {
setText(""); setText("");
setExpanded(false);
setShowAddConfirm(true);
enqueueHideAddConfirm();
} }
} }
} else { } else {
...@@ -45,8 +79,40 @@ const AddPostForm = ({ className }) => { ...@@ -45,8 +79,40 @@ const AddPostForm = ({ className }) => {
} }
}; };
const wrapperClass = classNames(
className,
"hover:elevation-16 transition duration-500",
{
"elevation-4 cursor-text": !expanded,
"lg:elevation-16 container-padding--zero lg:container-padding--auto": expanded,
}
);
return ( return (
<div className={className}> <Card className={wrapperClass} ref={cardRef}>
<span
className={classNames("alert items-center transition duration-500", {
"alert--success": showAddConfirm,
"alert--light": !showAddConfirm,
hidden: expanded,
})}
onClick={onWrite}
>
<i
className={classNames("alert__icon text-lg mr-4", {
"ico--checkmark": showAddConfirm,
"ico--pencil": !showAddConfirm,
})}
/>
{showAddConfirm && <span>Příspěvek byl přidán.</span>}
{!showAddConfirm && <span>Napiš nový příspěvek ...</span>}
</span>
<CardBody
className={
"p-4 lg:p-8 " + (showAddConfirm || !expanded ? "hidden" : "")
}
>
<div className="space-y-4">
{addingPostError && ( {addingPostError && (
<ErrorMessage> <ErrorMessage>
Při přidávání příspěvku došlo k problému: {addingPostError}. Při přidávání příspěvku došlo k problému: {addingPostError}.
...@@ -59,6 +125,7 @@ const AddPostForm = ({ className }) => { ...@@ -59,6 +125,7 @@ const AddPostForm = ({ className }) => {
)} )}
<MarkdownEditor <MarkdownEditor
ref={editorRef}
value={text} value={text}
onChange={onTextInput} onChange={onTextInput}
error={error} error={error}
...@@ -70,11 +137,19 @@ const AddPostForm = ({ className }) => { ...@@ -70,11 +137,19 @@ const AddPostForm = ({ className }) => {
]} ]}
/> />
<div className="form-field" onChange={(evt) => setType(evt.target.value)}> <div
className="form-field"
onChange={(evt) => setType(evt.target.value)}
>
<div className="form-field__wrapper form-field__wrapper--freeform flex-col sm:flex-row"> <div className="form-field__wrapper form-field__wrapper--freeform flex-col sm:flex-row">
<div className="radio form-field__control"> <div className="radio form-field__control">
<label> <label>
<input type="radio" name="postType" value="post" defaultChecked /> <input
type="radio"
name="postType"
value="post"
defaultChecked
/>
<span className="text-sm sm:text-base"> <span className="text-sm sm:text-base">
Přidávám <strong>běžný příspěvek</strong> Přidávám <strong>běžný příspěvek</strong>
</span> </span>
...@@ -83,7 +158,11 @@ const AddPostForm = ({ className }) => { ...@@ -83,7 +158,11 @@ const AddPostForm = ({ className }) => {
<div className="radio form-field__control ml-0 mt-4 sm:mt-0 sm:ml-4"> <div className="radio form-field__control ml-0 mt-4 sm:mt-0 sm:ml-4">
<label> <label>
<input type="radio" name="postType" value="procedure-proposal" /> <input
type="radio"
name="postType"
value="procedure-proposal"
/>
<span className="text-sm sm:text-base"> <span className="text-sm sm:text-base">
Přidávám <strong>návrh postupu</strong> Přidávám <strong>návrh postupu</strong>
</span> </span>
...@@ -110,6 +189,7 @@ const AddPostForm = ({ className }) => { ...@@ -110,6 +189,7 @@ const AddPostForm = ({ className }) => {
loading={addingPost || addingProposal} loading={addingPost || addingProposal}
fullwidth fullwidth
hoverActive hoverActive
className="text-sm xl:text-base"
> >
{type === "post" && "Přidat příspěvek"} {type === "post" && "Přidat příspěvek"}
{type === "procedure-proposal" && "Navrhnout postup"} {type === "procedure-proposal" && "Navrhnout postup"}
...@@ -129,6 +209,8 @@ const AddPostForm = ({ className }) => { ...@@ -129,6 +209,8 @@ const AddPostForm = ({ className }) => {
</span> </span>
</div> </div>
</div> </div>
</CardBody>
</Card>
); );
}; };
......
...@@ -303,20 +303,12 @@ const Home = () => { ...@@ -303,20 +303,12 @@ const Home = () => {
<PostFilters /> <PostFilters />
</div> </div>
<PostsContainer
className="container-padding--zero lg:container-padding--auto"
showAddPostCta={programEntry.discussionOpened}
/>
{!programEntry.discussionOpened && {!programEntry.discussionOpened &&
(!isAuthenticated || (isAuthenticated && !user.isBanned)) && ( (!isAuthenticated || (isAuthenticated && !user.isBanned)) && (
<p className="leading-normal"> <p className="leading-normal">
Rozprava je uzavřena - příspěvky teď nelze přidávat. Rozprava je uzavřena - příspěvky teď nelze přidávat.
</p> </p>
)} )}
{programEntry.discussionOpened &&
isAuthenticated &&
!user.isBanned && <AddPostForm className="my-8 space-y-4" />}
{programEntry.discussionOpened && {programEntry.discussionOpened &&
isAuthenticated && isAuthenticated &&
user.isBanned && ( user.isBanned && (
...@@ -325,6 +317,14 @@ const Home = () => { ...@@ -325,6 +317,14 @@ const Home = () => {
ti ho předsedající odebere. ti ho předsedající odebere.
</ErrorMessage> </ErrorMessage>
)} )}
{programEntry.discussionOpened &&
isAuthenticated &&
!user.isBanned && <AddPostForm className="mb-8" />}
<PostsContainer
className="container-padding--zero lg:container-padding--auto"
showAddPostCta={programEntry.discussionOpened}
/>
</section> </section>
</article> </article>
<ProgramEntryEditModal <ProgramEntryEditModal
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment