problem solved

This commit is contained in:
Andreas 2024-07-07 01:15:40 +02:00
parent dc66da7d00
commit 365e2e3982
2 changed files with 221 additions and 288 deletions

View File

@ -6,6 +6,7 @@ import { Attributes, where } from "@sequelize/core";
import { getCookieAuth, userIsAdmin } from '../../actions'; import { getCookieAuth, userIsAdmin } from '../../actions';
import { ActionResult } from '../../ActionResult'; import { ActionResult } from '../../ActionResult';
import { PostAttributesWithBuckets } from '@/models'; import { PostAttributesWithBuckets } from '@/models';
import { inspect } from 'util';
export async function deletePost(postID: number): Promise<ActionResult<boolean>> { export async function deletePost(postID: number): Promise<ActionResult<boolean>> {
await dbSync; await dbSync;
@ -30,7 +31,7 @@ export type GetPostsAttributes = {
export async function getPostsWithBucketsAndProject(): Promise<ActionResult<GetPostsAttributes[]>> { export async function getPostsWithBucketsAndProject(): Promise<ActionResult<GetPostsAttributes[]>> {
await dbSync; await dbSync;
if(! await userIsAdmin()) return {error:"Unauthorized, not fetching Posts."} if(! await userIsAdmin()) return {error:"Unauthorized, not fetching Posts."}
const posts = await Post.findAll({ const posts:Post[] = await Post.findAll({
include: [ include: [
{association: Post.associations.buckets, include: Bucket.associations.attachments}, {association: Post.associations.buckets, include: Bucket.associations.attachments},
{association: Post.associations.user}, {association: Post.associations.user},
@ -38,22 +39,7 @@ export async function getPostsWithBucketsAndProject(): Promise<ActionResult<GetP
nest: false nest: false
}); });
return {result:JSON.parse(JSON.stringify(posts.map((e:Post)=>{ return {result:JSON.parse(JSON.stringify(posts.map((e:Post)=>{
return { return inspect(e)
id: e.id,
title: e.title,
content: e.content,
description: e.description,
buckets: e.buckets ? e.buckets : [],
user: e.user,
project: {
id: e.project_id,
name: e.project ? e.project.name : "",
readableIdentifier: e.project ? e.project.readableIdentifier : "",
posts: e.project ? e.project.posts : []
},
createdAt: e.createdAt,
updatedAt: e.updatedAt
} as GetPostsAttributes
})))}; })))};
} }

View File

@ -1,296 +1,243 @@
import { GetPostsAttributes } from "@/app/lib/actions/entityManagement/post/postActions"; import { GetPostsAttributes } from "@/app/lib/actions/entitymanagement/post/postActions";
import { Post, Project, Bucket, PostBucket, Attachment } from "@/models"; import { Post, Project, Bucket, PostBucket, Attachment } from "@/models";
import { Attributes } from "@sequelize/core"; import { Attributes } from "@sequelize/core";
import { UUID } from "crypto"; import { UUID } from "crypto";
import { EntityEditorTextArea } from '../input/EntityEditorTextArea'; import { EntityEditorTextArea } from "../input/EntityEditorTextArea";
import { ChangeEvent, ChangeEventHandler, MouseEventHandler, useState } from "react";
import { import {
ChangeEventHandler, Accordion,
MouseEventHandler, AccordionBody,
useState, AccordionHeader,
} from "react"; AccordionItem,
import {
Accordion,
AccordionBody,
AccordionHeader,
AccordionItem,
} from "react-bootstrap"; } from "react-bootstrap";
export type PostTableCallbacks = { export type PostTableCallbacks = {
savePost: (p: Partial<Attributes<Post>>) => void; savePost: (p: Partial<Attributes<Post>>) => void;
refetch: () => any; refetch: () => any;
closeEditor: () => any; closeEditor: () => any;
uploadAttachment: () => any; uploadAttachment: () => any;
}; };
export type EditorState = { export type EditorState = {
isEditorOpen: boolean; isEditorOpen: boolean;
editorPost: GetPostsAttributes; editorPost: GetPostsAttributes;
}; };
export type EditorProps = { export type EditorProps = {
editorPost: GetPostsAttributes; editorPost: GetPostsAttributes;
projectList: { projectList: {
id: number; id: number;
readableIdentifier: string; readableIdentifier: string;
}[]; }[];
callbacks: PostTableCallbacks; callbacks: PostTableCallbacks;
}; };
export default function PostEditor({ export default function PostEditor({
editorPost, editorPost,
projectList, projectList,
callbacks, callbacks,
}: EditorProps) { }: EditorProps) {
// Setup State Hooks // Setup State Hooks
let [postContentState, setPostContentState] = useState(editorPost.content); let [postContentState, setPostContentState] = useState(editorPost.content);
let [postTitleState, setPostTitleState] = useState(editorPost.title); let [postTitleState, setPostTitleState] = useState(editorPost.title);
let [postProjectIDState, setPostProjectIDState] = useState( let [postProjectIDState, setPostProjectIDState] = useState(
editorPost.project.id editorPost.project.id
); );
// Handle changing the selected project using the dropdown select // Handle changing the selected project using the dropdown select
const projectSelectionChange: ChangeEventHandler<HTMLSelectElement> = (e) => const projectSelectionChange: ChangeEventHandler<HTMLSelectElement> = (e) =>
setPostProjectIDState(parseInt(e.target.value)); setPostProjectIDState(parseInt(e.target.value));
// Handle clicking the save button // Handle clicking the save button
const onClickSaveButton: MouseEventHandler<HTMLButtonElement> = (e) => { const onClickSaveButton: MouseEventHandler<HTMLButtonElement> = (e) => {
callbacks?.savePost({ callbacks?.savePost({
id: editorPost?.id as number, id: editorPost?.id as number,
content: postContentState as string, content: postContentState as string,
title: postTitleState as string, title: postTitleState as string,
project_id: postProjectIDState, project_id: postProjectIDState,
}); });
}; };
const onClickCancelButton: MouseEventHandler<HTMLButtonElement> = (e) => { const onClickCancelButton: MouseEventHandler<HTMLButtonElement> = (e) => {
callbacks?.closeEditor(); callbacks?.closeEditor();
}; };
return ( return (
<> <>
<form className="bg-light w-[100%] h-content p-1"> <form className="bg-light w-[100%] h-content p-1">
<h1 key="heading-editpost" className="m-2"> <h1 key="heading-editpost" className="m-2">
Edit Post Edit Post
</h1> </h1>
<h2 key="label-title" className="m-2"> <h2 key="label-title" className="m-2">
Title Title
</h2> </h2>
<input <input
key="input-title" key="input-title"
value={postTitleState} value={postTitleState}
onChange={(e) => setPostTitleState(e.target.value)} onChange={(e) => setPostTitleState(e.target.value)}
type="text" type="text"
className="m-2" className="m-2"
/> />
<h2 key="label-content" className="m-2"> <h2 key="label-content" className="m-2">
Content Content
</h2> </h2>
<EntityEditorTextArea <EntityEditorTextArea
contentHook={{ contentHook={{
state: postContentState, state: postContentState,
setState: setPostContentState setState: setPostContentState,
}} }}
className={ "w-[100%] min-h-auto h-content align-top text-start text-base line-clamp-6 m-2" } className={
> "w-[100%] min-h-auto h-content align-top text-start text-base line-clamp-6 m-2"
</EntityEditorTextArea> }
<h2 key="label-project" className="m-2"> ></EntityEditorTextArea>
Project <h2 key="label-project" className="m-2">
</h2> Project
<select </h2>
key="input-project" <select
onChange={projectSelectionChange} key="input-project"
name="projects" onChange={projectSelectionChange}
id="projects" name="projects"
defaultValue={editorPost?.project?.id} id="projects"
placeholder={editorPost?.project?.name} defaultValue={editorPost?.project?.id}
value={postProjectIDState} placeholder={editorPost?.project?.name}
className="m-2" value={postProjectIDState}
> className="m-2"
<option key="projectSelectionOpt-0" value={0}> >
unassigned <option key="projectSelectionOpt-0" value={0}>
</option> unassigned
{projectList?.map((p) => ( </option>
<option {projectList?.map((p) => (
key={`projectSelectionOpt-${p.id}`} <option key={`projectSelectionOpt-${p.id}`} value={p.id}>
value={p.id} {p.readableIdentifier}
> </option>
{p.readableIdentifier} ))}
</option> </select>
))} <h2 key="label-attachments">Attachments</h2>
</select> <table key="table-buckets" className="table table-striped">
<h2 key="label-attachments">Attachments</h2> <thead>
<table key="table-buckets" className="table table-striped"> <tr>
<thead> <td>Buckets</td>
<tr> </tr>
<td>Buckets</td> </thead>
</tr> <tbody>
</thead> {editorPost?.buckets ? (
<tbody> (() => {
{editorPost?.buckets ? ( let bucketMap: Map<UUID, Attributes<Bucket>> = new Map(
(() => { editorPost.buckets.map((b) => [b.id as UUID, b])
let bucketMap: Map< );
UUID, let bucketList:UUID[] = [...editorPost.buckets.map((b) => b.id)];
Attributes<Bucket> return bucketList.map((bucketID,i) => {
> = new Map( return (
editorPost.buckets.map((b) => [ <>
b.id as UUID, <tr
b, key={i}
]) >
); <Accordion>
let bucketList = [ <AccordionItem
...editorPost.buckets.map((b) => b.id), eventKey={bucketList.indexOf(bucketID).toString()}
]; >
return bucketList.map((e) => { <AccordionHeader>{bucketID}</AccordionHeader>
return ( <AccordionBody>
<> <ul>
<tr <li>
key={`bucketAccordionRow-${bucketList <input
.indexOf(e) type="file"
.toString()}`} className="btn btn-success"
> onChange={onFileInputChange()}
<Accordion> />
<AccordionItem </li>
eventKey={bucketList {(() => {
.indexOf(e) const bucket: Attributes<Bucket> | undefined = bucketMap.get(bucketID);
.toString()} return bucket && bucket.attachments && (
> bucket.attachments.map((attachment) => (
<AccordionHeader> <li
{e} key={`listItem-file-${attachment.filename}`}
</AccordionHeader> >
<AccordionBody> {attachment.filename}
<ul> </li>
<li> ))
<input );
type="file" })()}
className="btn btn-success" </ul>
onChange={( </AccordionBody>
e </AccordionItem>
) => { </Accordion>
for ( </tr>
let index = 0; </>
index < );
(( });
e })()
.target ) : (
.files as FileList <></>
) )}
.length as number); </tbody>
index++ </table>
) { <button type="button" className="m-2 btn btn-primary">
const element = Preview
( </button>
e <button
.target type="button"
.files as FileList className="m-2 btn btn-success"
)[ onClick={onClickSaveButton}
index >
]; Save
const fReader = </button>
new FileReader(); <button
fReader.readAsDataURL( type="button"
element className="m-2 btn btn-danger"
); onClick={onClickCancelButton}
fReader.onloadend = >
( Cancel
event </button>
) => { </form>
console.log( </>
event );
.target
?.result
);
};
}
}}
/>
</li>
{(() => {
const bucket =
bucketMap.get(
e as UUID
);
return bucket &&
bucket.attachments ? (
bucket.attachments.map(
(
attachment
) => (
<li
key={`listItem-file-${attachment.filename}`}
>
{
attachment.filename
}
</li>
)
)
) : (
<></>
);
})()}
</ul>
</AccordionBody>
</AccordionItem>
</Accordion>
</tr>
</>
);
});
})()
) : (
<></>
)}
</tbody>
</table>
<button type="button" className="m-2 btn btn-primary">
Preview
</button>
<button
type="button"
className="m-2 btn btn-success"
onClick={onClickSaveButton}
>
Save
</button>
<button
type="button"
className="m-2 btn btn-danger"
onClick={onClickCancelButton}
>
Cancel
</button>
</form>
</>
);
} }
type EditorRendererProps = { type EditorRendererProps = {
editorPost: GetPostsAttributes; editorPost: GetPostsAttributes;
headings: string[]; headings: string[];
editorState: EditorState; editorState: EditorState;
editorControls: any; editorControls: any;
callbacks: any; callbacks: any;
projects: any; projects: any;
}; };
export function EditorRenderer({ function onFileInputChange(): ChangeEventHandler<HTMLInputElement> {
editorPost, return (e: ChangeEvent<HTMLInputElement>) => {
headings, for (let index = 0; index <
editorState, ((e.target.files as FileList)
callbacks, .length as number); index++) {
projects, const element = (
}: EditorRendererProps) { e.target.files as FileList
return editorState.isEditorOpen && )[index];
editorState.editorPost && const fReader = new FileReader();
editorState.editorPost.id == editorPost.id ? ( fReader.readAsDataURL(element);
<tr> fReader.onloadend = (event) => {
<th scope="row" colSpan={headings.length}> console.log(event.target?.result);
<PostEditor };
callbacks={callbacks} }
editorPost={editorState.editorPost} };
projectList={projects} }
/>
</th> export function EditorRenderer({
</tr> editorPost,
) : ( headings,
"" editorState,
); callbacks,
projects,
}: EditorRendererProps) {
return editorState.isEditorOpen &&
editorState.editorPost &&
editorState.editorPost.id == editorPost.id ? (
<tr>
<th scope="row" colSpan={headings.length}>
<PostEditor
callbacks={callbacks}
editorPost={editorState.editorPost}
projectList={projects}
/>
</th>
</tr>
) : (
""
);
} }