|
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> |
|
) |
|
} |