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
Branches
No related tags found
No related merge requests found
......@@ -1426,6 +1426,16 @@
"resolved": "https://registry.npmjs.org/@rooks/use-interval/-/use-interval-4.5.0.tgz",
"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": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@rooks/use-window-size/-/use-window-size-4.5.0.tgz",
......
......@@ -78,7 +78,7 @@ const AnnouncementEditModal = ({
return (
<Modal containerClassName="max-w-lg" onRequestClose={onCancel} {...props}>
<form onSubmit={confirm}>
<Card>
<Card className="elevation-21">
<CardBody>
<div className="flex items-center justify-between mb-4">
<CardHeadline>Upravit oznámení</CardHeadline>
......
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>;
const Card = ({ children, className }, ref) => {
const cls = classNames("card", className);
return (
<div className={cls} ref={ref}>
{children}
</div>
);
};
export default Card;
export default React.forwardRef(Card);
import React from "react";
import classNames from "classnames";
const CardBody = ({ children, className }) => {
const CardBody = ({ children, className, ...props }) => {
const cls = classNames("card__body", className);
return <div className={cls}>{children}</div>;
return (
<div className={cls} {...props}>
{children}
</div>
);
};
export default CardBody;
......@@ -7,13 +7,10 @@ import { markdownConverter } from "markdown";
import "react-mde/lib/styles/css/react-mde-toolbar.css";
import "./MarkdownEditor.css";
const MarkdownEditor = ({
value,
onChange,
error,
placeholder = "",
...props
}) => {
const MarkdownEditor = (
{ value, onChange, error, placeholder = "", ...props },
ref
) => {
const [selectedTab, setSelectedTab] = useState("write");
const classes = {
......@@ -36,6 +33,7 @@ const MarkdownEditor = ({
return (
<div className={classNames("form-field", { "form-field--error": !!error })}>
<ReactMde
ref={ref}
value={value}
onChange={onChange}
selectedTab={selectedTab}
......@@ -53,4 +51,4 @@ const MarkdownEditor = ({
);
};
export default MarkdownEditor;
export default React.forwardRef(MarkdownEditor);
......@@ -21,7 +21,7 @@ const ModalConfirm = ({
}) => {
return (
<Modal onRequestClose={onClose} {...props}>
<Card>
<Card className="elevation-21">
<CardBody>
<div className="flex items-center justify-between mb-4">
<CardHeadline>{title}</CardHeadline>
......
......@@ -42,7 +42,7 @@ const PostEditModal = ({
return (
<Modal containerClassName="max-w-xl" onRequestClose={onCancel} {...props}>
<form onSubmit={confirm}>
<Card>
<Card className="elevation-21">
<CardBody>
<div className="flex items-center justify-between mb-4">
<CardHeadline>Upravit text příspěvku</CardHeadline>
......
......@@ -27,7 +27,7 @@ const RejectPostModalConfirm = ({
}) => {
return (
<Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}>
<Card>
<Card className="elevation-21">
<CardBody>
<div className="flex items-center justify-between mb-4">
<CardHeadline>{title}</CardHeadline>
......
......@@ -24,7 +24,7 @@ const ProgramEntryEditModal = ({
return (
<Modal containerClassName="max-w-md" onRequestClose={onCancel} {...props}>
<Card>
<Card className="elevation-21">
<CardBody>
<div className="flex items-center justify-between mb-4">
<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 Button from "components/Button";
import { Card, CardBody } from "components/cards";
import ErrorMessage from "components/ErrorMessage";
import MarkdownEditor from "components/mde/MarkdownEditor";
import { useActionState } from "hooks";
const AddPostForm = ({ className }) => {
const cardRef = useRef();
const editorRef = useRef();
const [expanded, setExpanded] = useState(false);
const [text, setText] = useState("");
const [showAddConfirm, setShowAddConfirm] = useState(false);
const [type, setType] = useState("post");
const [error, setError] = useState(null);
const [addingPost, addingPostError] = useActionState(addPost, {
......@@ -17,6 +25,29 @@ const AddPostForm = ({ className }) => {
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) => {
setText(newText);
......@@ -38,6 +69,9 @@ const AddPostForm = ({ className }) => {
if (!result.error) {
setText("");
setExpanded(false);
setShowAddConfirm(true);
enqueueHideAddConfirm();
}
}
} else {
......@@ -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 (
<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 && (
<ErrorMessage>
Při přidávání příspěvku došlo k problému: {addingPostError}.
......@@ -59,6 +125,7 @@ const AddPostForm = ({ className }) => {
)}
<MarkdownEditor
ref={editorRef}
value={text}
onChange={onTextInput}
error={error}
......@@ -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="radio form-field__control">
<label>
<input type="radio" name="postType" value="post" defaultChecked />
<input
type="radio"
name="postType"
value="post"
defaultChecked
/>
<span className="text-sm sm:text-base">
Přidávám <strong>běžný příspěvek</strong>
</span>
......@@ -83,7 +158,11 @@ const AddPostForm = ({ className }) => {
<div className="radio form-field__control ml-0 mt-4 sm:mt-0 sm:ml-4">
<label>
<input type="radio" name="postType" value="procedure-proposal" />
<input
type="radio"
name="postType"
value="procedure-proposal"
/>
<span className="text-sm sm:text-base">
Přidávám <strong>návrh postupu</strong>
</span>
......@@ -110,6 +189,7 @@ const AddPostForm = ({ className }) => {
loading={addingPost || addingProposal}
fullwidth
hoverActive
className="text-sm xl:text-base"
>
{type === "post" && "Přidat příspěvek"}
{type === "procedure-proposal" && "Navrhnout postup"}
......@@ -129,6 +209,8 @@ const AddPostForm = ({ className }) => {
</span>
</div>
</div>
</CardBody>
</Card>
);
};
......
......@@ -303,20 +303,12 @@ const Home = () => {
<PostFilters />
</div>
<PostsContainer
className="container-padding--zero lg:container-padding--auto"
showAddPostCta={programEntry.discussionOpened}
/>
{!programEntry.discussionOpened &&
(!isAuthenticated || (isAuthenticated && !user.isBanned)) && (
<p className="leading-normal">
Rozprava je uzavřena - příspěvky teď nelze přidávat.
</p>
)}
{programEntry.discussionOpened &&
isAuthenticated &&
!user.isBanned && <AddPostForm className="my-8 space-y-4" />}
{programEntry.discussionOpened &&
isAuthenticated &&
user.isBanned && (
......@@ -325,6 +317,14 @@ const Home = () => {
ti ho předsedající odebere.
</ErrorMessage>
)}
{programEntry.discussionOpened &&
isAuthenticated &&
!user.isBanned && <AddPostForm className="mb-8" />}
<PostsContainer
className="container-padding--zero lg:container-padding--auto"
showAddPostCta={programEntry.discussionOpened}
/>
</section>
</article>
<ProgramEntryEditModal
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment