96 lines
4.2 KiB
TypeScript
96 lines
4.2 KiB
TypeScript
import { ActionResult } from "@/app/lib/actions/ActionResult";
|
|
import { handleActionResult } from "@/app/lib/actions/clientActionHandler";
|
|
import { Post, Project, Bucket, PostBucket, Attachment } from "@/model/Models";
|
|
import { Attributes } from "@sequelize/core";
|
|
import { UUID } from "crypto";
|
|
import { ChangeEventHandler, MouseEventHandler, useLayoutEffect, useRef, useState } from "react";
|
|
import { Accordion, AccordionBody, AccordionHeader, AccordionItem } from "react-bootstrap";
|
|
|
|
export type PostTableCallbacks = {
|
|
savePost: (p:Partial<Attributes<Post>>)=>any;
|
|
closeEditor: ()=>any;
|
|
}
|
|
type PostEditorBucket = Partial<Attributes<Bucket>> & {
|
|
attachments:Partial<Attributes<Attachment>>[]
|
|
}
|
|
|
|
type PostEditorPost = Partial<Attributes<Post>> & {
|
|
buckets:PostEditorBucket[]
|
|
}
|
|
|
|
export type EditorProps = {
|
|
open:boolean;
|
|
post:PostEditorPost;
|
|
projects?:Attributes<Project>[];
|
|
callbacks:PostTableCallbacks;
|
|
}
|
|
|
|
|
|
export default function PostEditor(props:EditorProps){
|
|
let [content,setContent] = useState(props.post?.content)
|
|
let [title,setTitle] = useState(props.post?.title)
|
|
let [projectID,setProjectID] = useState(props.post?.project_id)
|
|
let textbox:any = useRef(undefined);
|
|
|
|
function adjustHeight() {
|
|
if(!textbox.current || !textbox.current.style) return
|
|
textbox.current.style.height = "fit-content";
|
|
textbox.current.style.height = `${textbox.current.scrollHeight}px`;
|
|
}
|
|
|
|
useLayoutEffect(adjustHeight, []);
|
|
|
|
const onTextAreaChange:ChangeEventHandler<HTMLTextAreaElement> = (e) => {setContent(e.target.value);adjustHeight()};
|
|
const projectSelectionChange:ChangeEventHandler<HTMLSelectElement> = (e)=>setProjectID(parseInt(e.target.value));
|
|
const onClickSaveButton:MouseEventHandler<HTMLButtonElement> = (e)=>{
|
|
props.callbacks.savePost({
|
|
id: props.post.id as number,
|
|
content:content as string,
|
|
title:title as string,
|
|
});
|
|
}
|
|
const onClickCancelButton:MouseEventHandler<HTMLButtonElement> = (e)=>{props.callbacks.closeEditor();}
|
|
|
|
return <>
|
|
<form className="bg-light w-[100%] h-content p-1">
|
|
<h1 className="m-2">Edit Post</h1>
|
|
<h2 className="m-2">Title</h2>
|
|
<input value={title} onChange={e => setTitle(e.target.value)} type='text' className="m-2"></input>
|
|
<h2 className="m-2">Content</h2>
|
|
<textarea onChange={onTextAreaChange} ref={textbox} value={content} style={{"height" : "100%"}} className="w-[100%] min-h-auto h-content align-top text-start text-base line-clamp-6 m-2"></textarea>
|
|
<h2 className="m-2">Project</h2>
|
|
<select onChange={projectSelectionChange} name="projects" id="projects" defaultValue={props.post?.project?.id} placeholder={props.post?.project?.name} value={projectID} className="m-2">
|
|
<option value={0}>unassigned</option>
|
|
{props.projects?.map(p=><option value={p.id}>{p.readableIdentifier}</option>)}
|
|
</select>
|
|
<h2>Attachments</h2>
|
|
<table className="table table-striped">
|
|
<thead>
|
|
<tr><td>Buckets</td></tr>
|
|
</thead>
|
|
<tbody>
|
|
{
|
|
(()=>{
|
|
let bucketMap:Map<UUID,PostEditorBucket> = new Map(props.post.buckets.map((b)=>[b.id as UUID,b]));
|
|
let bucketList = [...props.post.buckets.map((b)=>b.id)];
|
|
return bucketList.map((e)=>{
|
|
return <tr><Accordion><AccordionItem eventKey={bucketList.indexOf(e).toString()}><AccordionHeader>{e}</AccordionHeader><AccordionBody><ul>{bucketMap.get(e as UUID)?.attachments.map((attachment)=><li>{attachment.filename}</li>)}</ul></AccordionBody></AccordionItem></Accordion></tr>
|
|
})
|
|
})()
|
|
}
|
|
<tr>
|
|
<td colSpan={4}>
|
|
<table className="table mb-0">
|
|
...
|
|
</table>
|
|
</td>
|
|
</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>
|
|
</>
|
|
} |