Skip to content

Commit

Permalink
Merge pull request #624 from alan-turing-institute/437-element-comments
Browse files Browse the repository at this point in the history
437 element comments
  • Loading branch information
RichGriff authored Sep 28, 2024
2 parents 2dd9fcb + 916245c commit 305090a
Show file tree
Hide file tree
Showing 8 changed files with 617 additions and 6 deletions.
128 changes: 128 additions & 0 deletions next_frontend/components/cases/CommentForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, { Dispatch, SetStateAction, useState } from 'react'
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { z } from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { Textarea } from "../ui/textarea"
import { Button } from '../ui/button'
import useStore from '@/data/store';
import { useLoginToken } from '@/hooks/useAuth'
import { addElementComment } from '@/lib/case-helper'

const formSchema = z.object({
comment: z.string().min(2, {
message: "Comment must be atleast 2 characters"
})
})

interface CommentsFormProps {
node: any
};

const CommentsForm: React.FC<CommentsFormProps> = ({ node }: CommentsFormProps) => {
const { assuranceCase, setAssuranceCase, nodeComments, setNodeComments } = useStore();
const [token] = useLoginToken();
const [loading, setLoading] = useState(false)

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
comment: ''
}
});

async function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values)
setLoading(true)

let newComment = {
content: values.comment
} as any

let entity = null;
switch (node.type) {
case "context":
entity = "contexts";
newComment.context = node.data.id
break;
case "strategy":
entity = "strategies";
newComment.strategy = node.data.id
break;
case "property":
entity = "propertyclaims";
newComment.property_claim = node.data.id
break;
case "evidence":
entity = "evidence";
newComment.evidence = node.data.id
break;
default:
entity = "goals";
newComment.goal = node.data.id
break;
}

try {
let url = `${process.env.NEXT_PUBLIC_API_URL}/api/${entity}/${node.data.id}/comments/`;

const requestOptions: RequestInit = {
method: "POST",
headers: {
Authorization: `Token ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(newComment)
};

const response = await fetch(url, requestOptions);
const result = await response.json()

// **Update the comments as an array**
const newCommentsList = [...nodeComments, result]

setNodeComments(newCommentsList)

// Clear form input
form.setValue('comment', '')
} catch (error) {
console.log('Error', error)
} finally {
setLoading(false)
}
}

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 mt-2 w-full">
<FormField
control={form.control}
name="comment"
render={({ field }) => (
<FormItem>
<FormLabel className='hidden'>New Comment</FormLabel>
<FormControl>
<Textarea placeholder="Type your comment here." rows={5} {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className='flex justify-start items-center gap-3'>
<Button type="submit" disabled={loading} className="bg-indigo-500 hover:bg-indigo-600 text-white">
{loading ? 'Adding...' : 'Add Comment'}
</Button>
</div>
</form>
</Form>
)
}

export default CommentsForm
146 changes: 146 additions & 0 deletions next_frontend/components/cases/CommentsEditForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
'use client'

import React, { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react'
import { boolean, z } from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { Button } from "@/components/ui/button"
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Textarea } from '../ui/textarea'
import { useLoginToken } from '@/hooks/useAuth'
import useStore from '@/data/store'
import { updateElementComment } from '@/lib/case-helper'
import { useToast } from '../ui/use-toast'

type CommentsEditFormProps = {
node: any
comment: any
setEdit: Dispatch<SetStateAction<boolean>>
}

const formSchema = z.object({
comment: z.string().min(2).max(500),
})

const CommentsEditForm = ({ node, comment, setEdit } : CommentsEditFormProps ) => {
const [token] = useLoginToken();
const { assuranceCase, setAssuranceCase, nodeComments, setNodeComments } = useStore()
const [loading, setLoading] = useState<boolean>(false)
const textareaRef = useRef<HTMLTextAreaElement | null>(null); // Ref for the textarea

const { id: commentId, content } = comment
const { toast } = useToast();

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
comment: content,
}
})

async function onSubmit(values: z.infer<typeof formSchema>) {
setLoading(true)

const newComment = {
content: values.comment
}

try {
let url = `${process.env.NEXT_PUBLIC_API_URL}/api/comments/${commentId}/`

const requestOptions: RequestInit = {
method: "PUT",
headers: {
Authorization: `Token ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(newComment),
};
const response = await fetch(url, requestOptions);

if(!response.ok) {
toast({
variant: 'destructive',
title: 'Failed to update comment',
description: 'Something went wrong trying to update the comment.',
});
return
}

const updatedComment = await response.json();

// Find the index of the updated comment in the existing comments array
const updatedComments = nodeComments.map((comment:any) =>
comment.id === updatedComment.id ? updatedComment : comment
);

setNodeComments(updatedComments);
setEdit(false);
} catch (error) {
toast({
variant: 'destructive',
title: 'Failed to update comment',
description: 'Something went wrong trying to update the comment.',
});
} finally {
setLoading(false)
}
}

// Function to adjust the textarea height dynamically
const autoResizeTextarea = () => {
if (textareaRef.current) {
textareaRef.current.style.height = 'auto'; // Reset the height
textareaRef.current.style.height = textareaRef.current.scrollHeight + 'px'; // Set the height to match content
}
}

// Resize the textarea when the content or the form loads
useEffect(() => {
autoResizeTextarea(); // Initial resize
}, [form.watch('comment')]) // Re-run when the comment changes

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="comment"
render={({ field }) => (
<FormItem>
<FormControl>
<Textarea
placeholder="Type your message here."
{...field}
ref={(e) => {
field.ref(e); // Integrate with react-hook-form
textareaRef.current = e; // Set the local ref
}}
onInput={autoResizeTextarea} // Auto-resize on input
style={{ overflow: 'hidden' }} // Hide scrollbars
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className='flex justify-end items-center gap-2'>
<Button variant={'ghost'} className={'hover:bg-indigo-800/50'} onClick={() => setEdit(false)}>Cancel</Button>
<Button type="submit" disabled={loading}>
{loading ? 'Saving' : 'Save'}
</Button>
</div>
</form>
</Form>
)
}

export default CommentsEditForm
Loading

0 comments on commit 305090a

Please sign in to comment.