Skip to content

Commit

Permalink
Merge pull request #193 from pedrolivaresanchez/feat/comments
Browse files Browse the repository at this point in the history
Comentarios en los casos
  • Loading branch information
Pinx0 authored Nov 11, 2024
2 parents da0507b + d86f009 commit 873362b
Show file tree
Hide file tree
Showing 12 changed files with 377 additions and 197 deletions.
2 changes: 2 additions & 0 deletions src/app/solicitudes/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useQuery } from '@tanstack/react-query';
import { HelpRequestData } from '@/types/Requests';
import { helpRequestService } from '@/lib/service';
import { useParams } from 'next/navigation';
import SolicitudComments from '@/components/Comments/SolicitudComments';

export default function CasoDetalle() {
const { id } = useParams<{ id: string }>();
Expand Down Expand Up @@ -55,6 +56,7 @@ export default function CasoDetalle() {
</button>
</div>
<SolicitudCard caso={request} showLink={false} showEdit={true} />
<SolicitudComments request={request} />
</div>
);
}
13 changes: 7 additions & 6 deletions src/components/AsignarSolicitudButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ export default function AsignarSolicitudButton({ helpRequest }: AsignarSolicitud
phone_number: session.user.user_metadata.telefono!,
});
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['help_request_assignments'] });
queryClient.invalidateQueries({ queryKey: ['help_requests', { user_id: userId, type: 'necesita' }] });
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ['help_request_assignments'] });
await queryClient.invalidateQueries({ queryKey: ['help_requests', { user_id: userId, type: 'necesita' }] });
await router.push(`/solicitudes/${helpRequest.id}`);
},
onError: (e) => {
console.error('Error al asignarte a la petición de ayuda', e);
Expand All @@ -58,9 +59,9 @@ export default function AsignarSolicitudButton({ helpRequest }: AsignarSolicitud
if (!userAssignment) return;
await helpRequestService.unassign(userAssignment.id);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['help_request_assignments'] });
queryClient.invalidateQueries({ queryKey: ['help_requests', { user_id: userId, type: 'necesita' }] });
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ['help_request_assignments'] });
await queryClient.invalidateQueries({ queryKey: ['help_requests', { user_id: userId, type: 'necesita' }] });
},
onError: (e) => {
console.error('Error al asignarte a la petición de ayuda', e);
Expand Down
78 changes: 78 additions & 0 deletions src/components/Comments/CommentForm.tsx
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>
);
}
41 changes: 41 additions & 0 deletions src/components/Comments/DeleteCommentButton.tsx
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>
);
}
56 changes: 56 additions & 0 deletions src/components/Comments/SolicitudComment.tsx
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>
);
}
69 changes: 69 additions & 0 deletions src/components/Comments/SolicitudComments.tsx
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>
);
}
2 changes: 1 addition & 1 deletion src/components/SolicitudCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default function SolicitudCard({
</div>
</div>
<div className="flex flex-row justify-center items-center gap-2">
<SolicitudHelpCount id={caso.id} people={caso.number_of_people} />
<SolicitudHelpCount id={caso.id} />
<div
className={`flex items-center justify-center rounded-full px-4 py-2 ${
updateStatus === 'finished'
Expand Down
9 changes: 2 additions & 7 deletions src/components/SolicitudHelpCount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import { Spinner } from '@/components/Spinner';

type SolicitudHelpCountProps = {
id: number;
people: any;
};

export default function SolicitudHelpCount({ id, people }: SolicitudHelpCountProps) {
export default function SolicitudHelpCount({ id }: SolicitudHelpCountProps) {
const {
data: assignments,
isLoading,
Expand All @@ -24,14 +23,10 @@ export default function SolicitudHelpCount({ id, people }: SolicitudHelpCountPro

const volunteers = assignments.length;

const volunteerPercentage = (volunteers / people) * 100;

let colorClass: string;

if (volunteerPercentage < 33) {
if (volunteers === 0) {
colorClass = 'bg-red-100 text-red-800';
} else if (volunteerPercentage >= 33 && volunteerPercentage < 66) {
colorClass = 'bg-yellow-100 text-yellow-800';
} else {
colorClass = 'bg-green-100 text-green-800';
}
Expand Down
Loading

0 comments on commit 873362b

Please sign in to comment.