| import {Post as PostType, Topic as TopicType, topicsCtx} from "@/contexts/topics"; |
| import style from "./style.module.scss"; |
| import {Preview} from "../preview"; |
| import {iso8601ToFrench} from "@/utils/dates"; |
| import {FormGroup} from "../form"; |
| import {Slider} from "../slider"; |
| import {Button} from "../button"; |
| import {settingsCtx} from "@/contexts/settings"; |
| import {useContext, useState, useMemo} from "preact/hooks"; |
| import {Wysiwyg} from "@/components/wysiwyg"; |
| import { |
| ChevronRight, |
| X, |
| } from "preact-feather"; |
| import cn from "classnames"; |
| import {Pagination} from "@/components/pagination"; |
| import {Spinner} from "@/components/spinner"; |
| import {logCtx} from "@/contexts/log"; |
|
|
| const postsPerPage = 10; |
|
|
| export function Topic(props: { |
| topic: TopicType, |
| page: number, |
| setPage: (newPage: number) => void, |
| }) { |
| |
| |
| |
| |
| |
| |
| const [topicsContext, , topicsActions] = useContext(topicsCtx); |
| const [settings, setSettings] = useContext(settingsCtx); |
| const [, , logActions] = useContext(logCtx); |
| const [wysiwygText, setWysiwygText] = useState(""); |
|
|
| const addQuote = (post: PostType) => { |
| setWysiwygText((wysiwygText.length > 1 ? `${wysiwygText}\n\n` : "") + post.content.split("\n").map(l => `> ${l}`).join("\n")) |
| } |
|
|
| const postsSlice = useMemo( |
| () => props.topic.posts.slice(props.page * postsPerPage, (props.page + 1) * postsPerPage), |
| [props.page, props.topic.posts] |
| ); |
|
|
| const pendingGeneration = topicsContext.generation === "pending"; |
|
|
| const pagination = ( |
| <Pagination |
| pageCount={Math.ceil(props.topic.posts.length / postsPerPage)} |
| page={props.page} |
| setPage={props.setPage} |
| /> |
| ); |
|
|
| return ( |
| <div> |
| <div className={style.wrapper}> |
| {pagination} |
| <div className={style.postsContainer}> |
| {postsSlice.map((post, index) => { |
| const realIndex = postsPerPage * props.page + index; |
| return ( |
| <Post |
| post={post} |
| quote={() => addQuote(post)} |
| remove={() => topicsActions.deletePost(props.topic.id, realIndex)} |
| loading={pendingGeneration && realIndex >= props.topic.posts.length - 1} |
| /> |
| ) |
| })} |
| </div> |
| {pagination} |
| </div> |
| <div> |
| <h2>Ajout de posts</h2> |
| <div className={style.generationSettings}> |
| <FormGroup> |
| <label htmlFor="postCount">Nombre de posts</label> |
| <Slider |
| name="postCount" |
| value={settings.postCount} |
| onChange={(v) => setSettings({...settings, postCount: v})} |
| min={1} |
| max={10} |
| step={1} |
| /> |
| </FormGroup> |
| </div> |
| <Button |
| onClick={() => topicsActions.generatePosts(settings, logActions.log, props.topic)} |
| secondary={true} |
| loading={pendingGeneration} |
| > |
| {pendingGeneration ? "Génération en cours…" : "Générer"} |
| </Button> |
| </div> |
| <hr/> |
| <div> |
| <Wysiwyg |
| showTitle={false} |
| onSubmit={(user, title, text) => { |
| topicsActions.addPost(props.topic.id, user, text) |
| }} |
| text={wysiwygText} |
| setText={setWysiwygText} |
| /> |
| </div> |
| </div> |
| ) |
| } |
|
|
| function Post(props: { |
| post: PostType, |
| quote: () => void, |
| remove: () => void, |
| loading: boolean, |
| }) { |
| return ( |
| <div className={style.post}> |
| <div className={style.postHeader}> |
| <img src="https://image.jeuxvideo.com/avatar-sm/default.jpg" className={style.avatar} alt="ahi"/> |
| <div className={style.user}>{props.post.user}</div> |
| <div className={style.date}>{iso8601ToFrench(props.post.date)}</div> |
| <div className={style.actions}> |
| <div className={cn(style.action, style.actionDanger)} title="Supprimer" onClick={props.remove}> |
| <X size={16} style={{right: 0.6, top: 1.2}}/> |
| </div> |
| <div className={style.action} title="Citer" onClick={props.quote}> |
| <ChevronRight size={16} style={{left: 1.2}}/> |
| </div> |
| </div> |
| </div> |
| <Preview raw={props.post.content}/> |
| {props.loading ? <Spinner className={style.spinner}/> : null} |
| </div> |
| ) |
| } |