problem solved
This commit is contained in:
parent
dc66da7d00
commit
365e2e3982
@ -6,6 +6,7 @@ import { Attributes, where } from "@sequelize/core";
|
||||
import { getCookieAuth, userIsAdmin } from '../../actions';
|
||||
import { ActionResult } from '../../ActionResult';
|
||||
import { PostAttributesWithBuckets } from '@/models';
|
||||
import { inspect } from 'util';
|
||||
|
||||
export async function deletePost(postID: number): Promise<ActionResult<boolean>> {
|
||||
await dbSync;
|
||||
@ -30,7 +31,7 @@ export type GetPostsAttributes = {
|
||||
export async function getPostsWithBucketsAndProject(): Promise<ActionResult<GetPostsAttributes[]>> {
|
||||
await dbSync;
|
||||
if(! await userIsAdmin()) return {error:"Unauthorized, not fetching Posts."}
|
||||
const posts = await Post.findAll({
|
||||
const posts:Post[] = await Post.findAll({
|
||||
include: [
|
||||
{association: Post.associations.buckets, include: Bucket.associations.attachments},
|
||||
{association: Post.associations.user},
|
||||
@ -38,22 +39,7 @@ export async function getPostsWithBucketsAndProject(): Promise<ActionResult<GetP
|
||||
nest: false
|
||||
});
|
||||
return {result:JSON.parse(JSON.stringify(posts.map((e:Post)=>{
|
||||
return {
|
||||
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
|
||||
return inspect(e)
|
||||
})))};
|
||||
}
|
||||
|
||||
|
||||
@ -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 { Attributes } from "@sequelize/core";
|
||||
import { UUID } from "crypto";
|
||||
import { EntityEditorTextArea } from '../input/EntityEditorTextArea';
|
||||
import { EntityEditorTextArea } from "../input/EntityEditorTextArea";
|
||||
import { ChangeEvent, ChangeEventHandler, MouseEventHandler, useState } from "react";
|
||||
import {
|
||||
ChangeEventHandler,
|
||||
MouseEventHandler,
|
||||
useState,
|
||||
} from "react";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionBody,
|
||||
AccordionHeader,
|
||||
AccordionItem,
|
||||
Accordion,
|
||||
AccordionBody,
|
||||
AccordionHeader,
|
||||
AccordionItem,
|
||||
} from "react-bootstrap";
|
||||
|
||||
export type PostTableCallbacks = {
|
||||
savePost: (p: Partial<Attributes<Post>>) => void;
|
||||
refetch: () => any;
|
||||
closeEditor: () => any;
|
||||
uploadAttachment: () => any;
|
||||
savePost: (p: Partial<Attributes<Post>>) => void;
|
||||
refetch: () => any;
|
||||
closeEditor: () => any;
|
||||
uploadAttachment: () => any;
|
||||
};
|
||||
|
||||
export type EditorState = {
|
||||
isEditorOpen: boolean;
|
||||
editorPost: GetPostsAttributes;
|
||||
isEditorOpen: boolean;
|
||||
editorPost: GetPostsAttributes;
|
||||
};
|
||||
|
||||
export type EditorProps = {
|
||||
editorPost: GetPostsAttributes;
|
||||
projectList: {
|
||||
id: number;
|
||||
readableIdentifier: string;
|
||||
}[];
|
||||
callbacks: PostTableCallbacks;
|
||||
editorPost: GetPostsAttributes;
|
||||
projectList: {
|
||||
id: number;
|
||||
readableIdentifier: string;
|
||||
}[];
|
||||
callbacks: PostTableCallbacks;
|
||||
};
|
||||
|
||||
export default function PostEditor({
|
||||
editorPost,
|
||||
projectList,
|
||||
callbacks,
|
||||
editorPost,
|
||||
projectList,
|
||||
callbacks,
|
||||
}: EditorProps) {
|
||||
// Setup State Hooks
|
||||
let [postContentState, setPostContentState] = useState(editorPost.content);
|
||||
let [postTitleState, setPostTitleState] = useState(editorPost.title);
|
||||
let [postProjectIDState, setPostProjectIDState] = useState(
|
||||
editorPost.project.id
|
||||
);
|
||||
// Setup State Hooks
|
||||
let [postContentState, setPostContentState] = useState(editorPost.content);
|
||||
let [postTitleState, setPostTitleState] = useState(editorPost.title);
|
||||
let [postProjectIDState, setPostProjectIDState] = useState(
|
||||
editorPost.project.id
|
||||
);
|
||||
|
||||
// Handle changing the selected project using the dropdown select
|
||||
const projectSelectionChange: ChangeEventHandler<HTMLSelectElement> = (e) =>
|
||||
setPostProjectIDState(parseInt(e.target.value));
|
||||
// Handle clicking the save button
|
||||
const onClickSaveButton: MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||
callbacks?.savePost({
|
||||
id: editorPost?.id as number,
|
||||
content: postContentState as string,
|
||||
title: postTitleState as string,
|
||||
project_id: postProjectIDState,
|
||||
});
|
||||
};
|
||||
const onClickCancelButton: MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||
callbacks?.closeEditor();
|
||||
};
|
||||
// Handle changing the selected project using the dropdown select
|
||||
const projectSelectionChange: ChangeEventHandler<HTMLSelectElement> = (e) =>
|
||||
setPostProjectIDState(parseInt(e.target.value));
|
||||
// Handle clicking the save button
|
||||
const onClickSaveButton: MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||
callbacks?.savePost({
|
||||
id: editorPost?.id as number,
|
||||
content: postContentState as string,
|
||||
title: postTitleState as string,
|
||||
project_id: postProjectIDState,
|
||||
});
|
||||
};
|
||||
const onClickCancelButton: MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||
callbacks?.closeEditor();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<form className="bg-light w-[100%] h-content p-1">
|
||||
<h1 key="heading-editpost" className="m-2">
|
||||
Edit Post
|
||||
</h1>
|
||||
<h2 key="label-title" className="m-2">
|
||||
Title
|
||||
</h2>
|
||||
<input
|
||||
key="input-title"
|
||||
value={postTitleState}
|
||||
onChange={(e) => setPostTitleState(e.target.value)}
|
||||
type="text"
|
||||
className="m-2"
|
||||
/>
|
||||
<h2 key="label-content" className="m-2">
|
||||
Content
|
||||
</h2>
|
||||
<EntityEditorTextArea
|
||||
contentHook={{
|
||||
state: postContentState,
|
||||
setState: setPostContentState
|
||||
}}
|
||||
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">
|
||||
Project
|
||||
</h2>
|
||||
<select
|
||||
key="input-project"
|
||||
onChange={projectSelectionChange}
|
||||
name="projects"
|
||||
id="projects"
|
||||
defaultValue={editorPost?.project?.id}
|
||||
placeholder={editorPost?.project?.name}
|
||||
value={postProjectIDState}
|
||||
className="m-2"
|
||||
>
|
||||
<option key="projectSelectionOpt-0" value={0}>
|
||||
unassigned
|
||||
</option>
|
||||
{projectList?.map((p) => (
|
||||
<option
|
||||
key={`projectSelectionOpt-${p.id}`}
|
||||
value={p.id}
|
||||
>
|
||||
{p.readableIdentifier}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<h2 key="label-attachments">Attachments</h2>
|
||||
<table key="table-buckets" className="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Buckets</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{editorPost?.buckets ? (
|
||||
(() => {
|
||||
let bucketMap: Map<
|
||||
UUID,
|
||||
Attributes<Bucket>
|
||||
> = new Map(
|
||||
editorPost.buckets.map((b) => [
|
||||
b.id as UUID,
|
||||
b,
|
||||
])
|
||||
);
|
||||
let bucketList = [
|
||||
...editorPost.buckets.map((b) => b.id),
|
||||
];
|
||||
return bucketList.map((e) => {
|
||||
return (
|
||||
<>
|
||||
<tr
|
||||
key={`bucketAccordionRow-${bucketList
|
||||
.indexOf(e)
|
||||
.toString()}`}
|
||||
>
|
||||
<Accordion>
|
||||
<AccordionItem
|
||||
eventKey={bucketList
|
||||
.indexOf(e)
|
||||
.toString()}
|
||||
>
|
||||
<AccordionHeader>
|
||||
{e}
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<ul>
|
||||
<li>
|
||||
<input
|
||||
type="file"
|
||||
className="btn btn-success"
|
||||
onChange={(
|
||||
e
|
||||
) => {
|
||||
for (
|
||||
let index = 0;
|
||||
index <
|
||||
((
|
||||
e
|
||||
.target
|
||||
.files as FileList
|
||||
)
|
||||
.length as number);
|
||||
index++
|
||||
) {
|
||||
const element =
|
||||
(
|
||||
e
|
||||
.target
|
||||
.files as FileList
|
||||
)[
|
||||
index
|
||||
];
|
||||
const fReader =
|
||||
new FileReader();
|
||||
fReader.readAsDataURL(
|
||||
element
|
||||
);
|
||||
fReader.onloadend =
|
||||
(
|
||||
event
|
||||
) => {
|
||||
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>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<form className="bg-light w-[100%] h-content p-1">
|
||||
<h1 key="heading-editpost" className="m-2">
|
||||
Edit Post
|
||||
</h1>
|
||||
<h2 key="label-title" className="m-2">
|
||||
Title
|
||||
</h2>
|
||||
<input
|
||||
key="input-title"
|
||||
value={postTitleState}
|
||||
onChange={(e) => setPostTitleState(e.target.value)}
|
||||
type="text"
|
||||
className="m-2"
|
||||
/>
|
||||
<h2 key="label-content" className="m-2">
|
||||
Content
|
||||
</h2>
|
||||
<EntityEditorTextArea
|
||||
contentHook={{
|
||||
state: postContentState,
|
||||
setState: setPostContentState,
|
||||
}}
|
||||
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">
|
||||
Project
|
||||
</h2>
|
||||
<select
|
||||
key="input-project"
|
||||
onChange={projectSelectionChange}
|
||||
name="projects"
|
||||
id="projects"
|
||||
defaultValue={editorPost?.project?.id}
|
||||
placeholder={editorPost?.project?.name}
|
||||
value={postProjectIDState}
|
||||
className="m-2"
|
||||
>
|
||||
<option key="projectSelectionOpt-0" value={0}>
|
||||
unassigned
|
||||
</option>
|
||||
{projectList?.map((p) => (
|
||||
<option key={`projectSelectionOpt-${p.id}`} value={p.id}>
|
||||
{p.readableIdentifier}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<h2 key="label-attachments">Attachments</h2>
|
||||
<table key="table-buckets" className="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Buckets</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{editorPost?.buckets ? (
|
||||
(() => {
|
||||
let bucketMap: Map<UUID, Attributes<Bucket>> = new Map(
|
||||
editorPost.buckets.map((b) => [b.id as UUID, b])
|
||||
);
|
||||
let bucketList:UUID[] = [...editorPost.buckets.map((b) => b.id)];
|
||||
return bucketList.map((bucketID,i) => {
|
||||
return (
|
||||
<>
|
||||
<tr
|
||||
key={i}
|
||||
>
|
||||
<Accordion>
|
||||
<AccordionItem
|
||||
eventKey={bucketList.indexOf(bucketID).toString()}
|
||||
>
|
||||
<AccordionHeader>{bucketID}</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<ul>
|
||||
<li>
|
||||
<input
|
||||
type="file"
|
||||
className="btn btn-success"
|
||||
onChange={onFileInputChange()}
|
||||
/>
|
||||
</li>
|
||||
{(() => {
|
||||
const bucket: Attributes<Bucket> | undefined = bucketMap.get(bucketID);
|
||||
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 = {
|
||||
editorPost: GetPostsAttributes;
|
||||
headings: string[];
|
||||
editorState: EditorState;
|
||||
editorControls: any;
|
||||
callbacks: any;
|
||||
projects: any;
|
||||
editorPost: GetPostsAttributes;
|
||||
headings: string[];
|
||||
editorState: EditorState;
|
||||
editorControls: any;
|
||||
callbacks: any;
|
||||
projects: any;
|
||||
};
|
||||
|
||||
export function EditorRenderer({
|
||||
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>
|
||||
) : (
|
||||
""
|
||||
);
|
||||
function onFileInputChange(): ChangeEventHandler<HTMLInputElement> {
|
||||
return (e: ChangeEvent<HTMLInputElement>) => {
|
||||
for (let index = 0; index <
|
||||
((e.target.files as FileList)
|
||||
.length as number); index++) {
|
||||
const element = (
|
||||
e.target.files as FileList
|
||||
)[index];
|
||||
const fReader = new FileReader();
|
||||
fReader.readAsDataURL(element);
|
||||
fReader.onloadend = (event) => {
|
||||
console.log(event.target?.result);
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function EditorRenderer({
|
||||
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>
|
||||
) : (
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user