-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #193 from pedrolivaresanchez/feat/comments
Comentarios en los casos
- Loading branch information
Showing
12 changed files
with
377 additions
and
197 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import React, { useState } from 'react'; | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import { helpRequestService } from '@/lib/service'; | ||
import { toast } from 'sonner'; | ||
import { useSession } from '@/context/SessionProvider'; | ||
|
||
interface CommentFormProps { | ||
helpRequestId: number; | ||
} | ||
|
||
export default function CommentForm({ helpRequestId }: CommentFormProps) { | ||
const queryClient = useQueryClient(); | ||
const [comment, setComment] = useState(''); | ||
const [isSolved, setIsSolved] = useState(false); | ||
const { user } = useSession(); | ||
|
||
const addCommentMutation = useMutation({ | ||
mutationFn: async () => helpRequestService.addComment(helpRequestId, comment, isSolved), | ||
onSuccess: () => { | ||
queryClient.invalidateQueries({ queryKey: ['comments', { request_id: helpRequestId }] }); | ||
setComment(''); | ||
setIsSolved(false); | ||
}, | ||
onError: (err: any) => { | ||
toast.error(err.message || 'Error al añadir el comentario'); | ||
}, | ||
}); | ||
|
||
const handleSubmit = (e: React.FormEvent) => { | ||
e.preventDefault(); | ||
addCommentMutation.mutate(); | ||
}; | ||
|
||
if (!user) return null; | ||
|
||
return ( | ||
<div className="rounded-2xl bg-white shadow-lg p-4 ring-1 ring-gray-900/5"> | ||
<form onSubmit={handleSubmit} className="space-y-4"> | ||
<div> | ||
<label htmlFor="comment" className="block font-medium text-gray-700"> | ||
Añadir comentario | ||
</label> | ||
<textarea | ||
id="comment" | ||
name="comment" | ||
rows={3} | ||
value={comment} | ||
onChange={(e) => setComment(e.target.value)} | ||
className="mt-1 p-4 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" | ||
placeholder="Escribe tu comentario aquí..." | ||
required | ||
/> | ||
</div> | ||
|
||
<div className="flex items-center"> | ||
<input | ||
id="isSolved" | ||
type="checkbox" | ||
checked={isSolved} | ||
onChange={(e) => setIsSolved(e.target.checked)} | ||
className="h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||
/> | ||
<label htmlFor="isSolved" className="ml-2 text-sm text-gray-700"> | ||
Marcar como caso solucionado | ||
</label> | ||
<div className={'flex-1'} /> | ||
<button | ||
type="submit" | ||
className="inline-flex justify-center py-2 px-4 shadow-sm font-semibold rounded-xl text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||
disabled={addCommentMutation.isPending} | ||
> | ||
{addCommentMutation.isPending ? 'Enviando...' : 'Enviar'} | ||
</button> | ||
</div> | ||
</form> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import React from 'react'; | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import { helpRequestService } from '@/lib/service'; | ||
import { toast } from 'sonner'; | ||
import { useSession } from '@/context/SessionProvider'; | ||
import { HelpRequestComment } from '@/types/Requests'; | ||
|
||
interface DeleteCommentFormProps { | ||
comment: HelpRequestComment; | ||
} | ||
|
||
export default function CommentForm({ comment }: DeleteCommentFormProps) { | ||
const queryClient = useQueryClient(); | ||
const { user } = useSession(); | ||
|
||
const removeCommentMutation = useMutation({ | ||
mutationFn: async () => helpRequestService.removeComment(comment.id), | ||
onSuccess: () => { | ||
queryClient.invalidateQueries({ queryKey: ['comments', { request_id: comment.help_request_id }] }); | ||
}, | ||
onError: (err: any) => { | ||
toast.error(err.message || 'Error al eliminar el comentario'); | ||
}, | ||
}); | ||
|
||
const handleSubmit = (e: React.FormEvent) => { | ||
e.preventDefault(); | ||
removeCommentMutation.mutate(); | ||
}; | ||
|
||
if (!user) return null; | ||
|
||
return ( | ||
<button | ||
onClick={handleSubmit} | ||
className="w-full text-center rounded-xl px-4 py-2 font-semibold text-white sm:w-auto transition-all bg-red-500 hover:bg-red-600" | ||
> | ||
{removeCommentMutation.isPending ? 'Eliminando...' : 'Eliminar'} | ||
</button> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { CheckCircle, Phone, User } from 'lucide-react'; | ||
import { HelpRequestComment } from '@/types/Requests'; | ||
import { useSession } from '@/context/SessionProvider'; | ||
import Link from 'next/link'; | ||
import DeleteCommentButton from './DeleteCommentButton'; | ||
import { useRole } from '@/context/RoleProvider'; | ||
|
||
type SolicitudCommentProps = { | ||
comment: HelpRequestComment; | ||
}; | ||
|
||
export default function SolicitudComment({ comment }: SolicitudCommentProps) { | ||
const { user } = useSession(); | ||
const role = useRole(); | ||
const isAdmin = role === 'admin'; | ||
const isMyComment = comment.user_id === user?.id; | ||
return ( | ||
<div key={comment.id} className="rounded-2xl bg-white shadow-lg ring-1 ring-gray-900/5 p-4"> | ||
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4"> | ||
<div className="flex flex-row items-center gap-4"> | ||
<div className="h-10 w-10 bg-gray-100 rounded-full flex items-center justify-center text-gray-500"> | ||
<User className="h-6 w-6" /> | ||
</div> | ||
<div className="flex flex-col"> | ||
<span className="font-semibold text-lg">{comment.user_name}</span> | ||
<span className="text-sm text-gray-500"> | ||
{new Date(comment.created_at!).toLocaleDateString()}{' '} | ||
{new Date(comment.created_at!).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} | ||
</span> | ||
</div> | ||
</div> | ||
<div className={'flex-1'} /> | ||
<Link | ||
href={`tel:${comment.user_phone}`} | ||
className="flex items-center gap-1 px-3 py-1 rounded-full bg-gray-100 text-gray-800" | ||
> | ||
<Phone className="h-4 w-4" /> | ||
<span className="text-sm font-semibold">{comment.user_phone}</span> | ||
</Link> | ||
|
||
{comment.is_solved && ( | ||
<div className="flex items-center gap-1 px-3 py-1 rounded-full bg-green-100 text-green-800"> | ||
<CheckCircle className="h-4 w-4" /> | ||
<span className="text-sm font-semibold">Caso solucionado</span> | ||
</div> | ||
)} | ||
</div> | ||
<div className="my-4"> | ||
<p className="text-gray-700" style={{ wordBreak: 'break-word' }}> | ||
{comment.comment} | ||
</p> | ||
</div> | ||
<div className={'flex justify-end'}>{(isMyComment || isAdmin) && <DeleteCommentButton comment={comment} />}</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { HelpRequestAssignmentData, HelpRequestComment, HelpRequestData } from '@/types/Requests'; | ||
import { useQuery } from '@tanstack/react-query'; | ||
import { helpRequestService } from '@/lib/service'; | ||
import { useSession } from '@/context/SessionProvider'; | ||
import SolicitudComment from '@/components/Comments/SolicitudComment'; | ||
import CommentForm from '@/components/Comments/CommentForm'; | ||
import { useRole } from '@/context/RoleProvider'; | ||
|
||
type SolicitudCommentsProps = { | ||
request: HelpRequestData; | ||
}; | ||
|
||
export default function SolicitudComments({ request }: SolicitudCommentsProps) { | ||
const { | ||
data: comments, | ||
isLoading, | ||
error, | ||
} = useQuery<HelpRequestComment[]>({ | ||
queryKey: ['comments', { request_id: request.id }], | ||
queryFn: () => helpRequestService.getComments(request.id), | ||
}); | ||
|
||
const { user } = useSession(); | ||
const role = useRole(); | ||
const isAdmin = role === 'admin'; | ||
|
||
const { | ||
data: assignments, | ||
isLoading: isLoadingAssignments, | ||
error: errorAssignments, | ||
} = useQuery<HelpRequestAssignmentData[]>({ | ||
queryKey: ['help_request_assignments', { id: request.id }], | ||
queryFn: () => helpRequestService.getAssignments(request.id), | ||
}); | ||
|
||
if (!user) return null; | ||
|
||
if (isLoading || isLoadingAssignments) | ||
return ( | ||
<div className="flex justify-center items-center min-h-screen"> | ||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div> | ||
</div> | ||
); | ||
|
||
if (error || comments === undefined || errorAssignments || assignments === undefined) { | ||
return ( | ||
<div className="space-y-6 mx-auto max-w-7xl px-4 sm:px-6"> | ||
<div className="bg-red-100 border-l-4 border-red-500 p-4 rounded"> | ||
<p className="text-red-700">Error al cargar los comentarios</p> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
const userAssignment = assignments.find((x) => x.user_id === user?.id); | ||
const userIsAssigned = !!userAssignment; | ||
const userIsOwner = user.id === request.user_id; | ||
|
||
if (!userIsAssigned && !isAdmin && !userIsOwner) return null; | ||
|
||
return ( | ||
<div className="space-y-4 pl-12 xl:pl-24"> | ||
{comments.map((comment) => ( | ||
<SolicitudComment comment={comment} key={comment.id} /> | ||
))} | ||
<CommentForm helpRequestId={request.id} /> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.