Skip to content

Commit

Permalink
Allow edit contact notification trigger
Browse files Browse the repository at this point in the history
  • Loading branch information
WalissonPires committed Sep 17, 2024
1 parent a7d5aaf commit a95015d
Show file tree
Hide file tree
Showing 13 changed files with 451 additions and 44 deletions.
75 changes: 65 additions & 10 deletions src/app/api/notifications/triggers/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,77 @@ import { NextRequest, NextResponse } from "next/server";
import { DeleteNotificationTrigger } from "@/domains/notification-triggers/use-cases/delete-notification-trigger";
import { PrismaClientFactory } from "@/common/database/prisma-factory";
import { UserSessionManager } from "@/domains/auth/services/user-session-maganer";
import { GetNotificationTrigger } from "@/domains/notification-triggers/use-cases/get-notification-trigger";
import { ApiErrorHandler } from "@/common/error/api-error-handler";
import { UpdateNotificationTriggerInput } from "@/domains/notification-triggers/use-cases/update-notification-trigger-types";
import { UpdateNotificationTrigger } from "@/domains/notification-triggers/use-cases/update-notification-trigger";
import { GenerateNotificationsByTriggers } from "@/domains/notifications/use-cases/generate-notification-by-triggers";

export async function GET(request: NextRequest, { params }: { params: RequestParams }) {

export async function DELETE(request: NextRequest, { params }: { params: DeleteParams }) {
try {
if (!params.id)
return NextResponse.json(null);

const useCase = new DeleteNotificationTrigger({
userLogged: await new UserSessionManager().getUserOrThrow(),
prismaClient: PrismaClientFactory.create()
});
const useCase = new GetNotificationTrigger({
userLogged: await new UserSessionManager().getUserOrThrow(),
prismaClient: PrismaClientFactory.create()
});

await useCase.execute({
id: params.id
});
const result = await useCase.execute({
triggerId: params.id
});

return new Response(null, { status: 204 });
return NextResponse.json(result);
}
catch(error) {
return ApiErrorHandler.handler(error);
}
}

interface DeleteParams {
export async function PUT(request: NextRequest) {

try {
const input: UpdateNotificationTriggerInput = await request.json();

const useCase = new UpdateNotificationTrigger({
userLogged: await new UserSessionManager().getUserOrThrow(),
prismaClient: PrismaClientFactory.create()
});

const trigger = await useCase.execute(input);

const generateNotificaion = new GenerateNotificationsByTriggers();
await generateNotificaion.execute({
triggerId: trigger.id
});

return NextResponse.json(trigger);
}
catch(error) {
return ApiErrorHandler.handler(error);
}
}

export async function DELETE(request: NextRequest, { params }: { params: RequestParams }) {

try {
const useCase = new DeleteNotificationTrigger({
userLogged: await new UserSessionManager().getUserOrThrow(),
prismaClient: PrismaClientFactory.create()
});

await useCase.execute({
id: params.id
});

return new Response(null, { status: 204 });
}
catch(error) {
return ApiErrorHandler.handler(error);
}
}

interface RequestParams {
id: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { AppLayout } from "@/components/AppLayout";
import { AppLayoutBackWithContactTitle } from "@/components/AppLayout/BackWithTitle/WithContact";
import { AppLayoutHeader } from "@/components/AppLayout/Header";
import { AppLayoutBody } from "@/components/AppLayout/Body";
import { AppLayoutPreLoading } from "@/components/AppLayout/PreLoading";
import { AppNavMenuDefault, AppNavMenuItens } from "@/components/AppLayout/NavMenu";
import { ValidationInit } from "@/components/ValidationInit";
import { NotificationView } from "@/components/NotificationView";

export default function ViewContactNotification({ params }: PageProps) {

return (
<AppLayout>
<AppLayoutHeader>
<AppLayoutBackWithContactTitle contactId={params.contactId} />
</AppLayoutHeader>
<AppLayoutBody>
<AppLayoutPreLoading>
<ValidationInit />
<NotificationView contactId={params.contactId} triggerId={params.triggerId} />
</AppLayoutPreLoading>
</AppLayoutBody>
<AppNavMenuDefault active={AppNavMenuItens.contacts} />
</AppLayout>
)
}

interface PageProps {
params: {
contactId: string;
triggerId: string;
}
}
1 change: 1 addition & 0 deletions src/common/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export abstract class AppRoutes {
public static importContacts() { return '/contacts/import'; }
public static viewContact(contactId: string) { return '/contacts/' + contactId; }
public static newContactNotification(contactId: string) { return `/contacts/${contactId}/notification-triggers/new`; }
public static viewContactNotification(contactId: string, triggerId: string) { return `/contacts/${contactId}/notification-triggers/${triggerId}`; }
public static contactNotificationTriggers(contactId: string) { return `/contacts/${contactId}/notification-triggers`; }
public static contactNotifications(contactId: string) { return `/contacts/${contactId}/notifications`; }
public static home() { return '/'; }
Expand Down
10 changes: 9 additions & 1 deletion src/components/ContactNotificationTriggersView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
'use client'

import { useRouter } from "next/navigation";
import { ArrowDownTrayIcon } from "@heroicons/react/24/outline";
import { AppError } from "@/common/error";
import { AppRoutes } from "@/common/routes";
import { AppToast } from "@/common/ui/toast";
import { NotificationTriggersApi } from "@/domains/notification-triggers/client-api";
import { Button } from "../Form";
Expand All @@ -13,6 +15,7 @@ export default function ContactNotificationTriggersView({ contactId }: ContactNo

const { data, isLoading: isLoadingTriggers, error, hasMore, loadNextPage, removeItem } = useNotificationTriggers({ contactId });
const { setLoading } = useLoading();
const router = useRouter();

const isEmpty = data.length == 0 && !isLoadingTriggers && !error;
const isFirstLoading = isLoadingTriggers && data.length === 0;
Expand All @@ -39,13 +42,18 @@ export default function ContactNotificationTriggersView({ contactId }: ContactNo
}
};

const handleEditTrigger = (triggerId: string) => async () => {

router.push(AppRoutes.viewContactNotification(contactId, triggerId));
};

return (
<div className="container mx-auto">
<div className="bg-white border m-4">
<ul className="divide-y">
{data.map(item =>
<li key={item.id}>
<NotificationTriggerCard trigger={item} onDeleteClick={handleDeleteTrigger(item.id)} />
<NotificationTriggerCard trigger={item} onEditClick={handleEditTrigger(item.id)} onDeleteClick={handleDeleteTrigger(item.id)} />
</li>)}
{isEmpty && <p className="text-center text-slate-400 p-4">Nenhuma notificação encontrada</p>}
{isFirstLoading && <NotificationTriggerCard.Skeleton />}
Expand Down
18 changes: 9 additions & 9 deletions src/components/Form/DaysOfMonthSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ export const DaysOfMonthSelect = forwardRef<HTMLSelectElement, SelectProps>(func

return (
<Select {...props} ref={ref}>
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
<option value="04">04</option>
<option value="05">05</option>
<option value="06">06</option>
<option value="07">07</option>
<option value="08">08</option>
<option value="09">09</option>
<option value="1">01</option>
<option value="2">02</option>
<option value="3">03</option>
<option value="4">04</option>
<option value="5">05</option>
<option value="6">06</option>
<option value="7">07</option>
<option value="8">08</option>
<option value="9">09</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
Expand Down
18 changes: 9 additions & 9 deletions src/components/Form/MonthsSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ export const MonthsSelect = forwardRef<HTMLSelectElement, SelectProps>(function

return (
<Select {...props} ref={ref}>
<option value="01">Janeiro</option>
<option value="02">Fevereiro</option>
<option value="03">Março</option>
<option value="04">Abril</option>
<option value="05">Maio</option>
<option value="06">Junho</option>
<option value="07">Julho</option>
<option value="08">Agosto</option>
<option value="09">Setembro</option>
<option value="1">Janeiro</option>
<option value="2">Fevereiro</option>
<option value="3">Março</option>
<option value="4">Abril</option>
<option value="5">Maio</option>
<option value="6">Junho</option>
<option value="7">Julho</option>
<option value="8">Agosto</option>
<option value="9">Setembro</option>
<option value="10">Outubro</option>
<option value="11">Novembro</option>
<option value="12">Dezembro</option>
Expand Down
8 changes: 6 additions & 2 deletions src/components/NotificationTriggerCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import { Info } from "luxon";
import { useMemo } from "react";
import Skeleton from "react-loading-skeleton";
import { EllipsisVerticalIcon, XMarkIcon } from "@heroicons/react/24/outline";
import { EllipsisVerticalIcon, PencilSquareIcon, XMarkIcon } from "@heroicons/react/24/outline";
import { Trigger1, TriggerType, TriggerTypeDisplay } from "@/domains/notification-triggers/entities";
import { DropdownMenu, DropdownMenuItem, DropdownMenuToggle } from "../Form";
import { useDrodownMenu } from "../Form/DropdownMenu/hooks";

export default function NotificationTriggerCard({ trigger, onDeleteClick }: NotificationTriggerCardProps) {
export default function NotificationTriggerCard({ trigger, onEditClick, onDeleteClick }: NotificationTriggerCardProps) {

const { templateMessage, type, day, month } = trigger;

Expand Down Expand Up @@ -40,6 +40,9 @@ export default function NotificationTriggerCard({ trigger, onDeleteClick }: Noti
<DropdownMenu
visible={visible}
toggle={<DropdownMenuToggle onClick={() => setVisible(!visible)}><EllipsisVerticalIcon className="h-5 w-5"/></DropdownMenuToggle>}>
<DropdownMenuItem onClick={onEditClick}>
<span><PencilSquareIcon className="h-5 w-5 inline-block" /> Editar</span>
</DropdownMenuItem>
<DropdownMenuItem onClick={onDeleteClick}>
<span><XMarkIcon className="h-5 w-5 inline-block" /> Excluir</span>
</DropdownMenuItem>
Expand Down Expand Up @@ -69,5 +72,6 @@ NotificationTriggerCard.Skeleton = function NotificationTriggerCardSkeleton() {

export interface NotificationTriggerCardProps {
trigger: Trigger1;
onEditClick: () => void;
onDeleteClick: () => void;
}
72 changes: 61 additions & 11 deletions src/components/NotificationView/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ import { useMessageTemplates } from "./message-templates.hook";

export interface UseNotificationViewProps {
contactId: string;
triggerId?: string;
}

export function useNotificationView({ contactId }: UseNotificationViewProps) {
export function useNotificationView({ contactId, triggerId }: UseNotificationViewProps) {

const [ isLoaded, setIsLoaded ] = useState(false);
const [ isSaving, setIsLoading ] = useState(false);
const { messageTemplates, isLoading: isLoadingMessageTemplates } = useMessageTemplates();
const router = useRouter();

const { register, handleSubmit, watch, setValue, formState: { errors }, control } = useForm<ValidationSchema>({
const { register, handleSubmit, watch, setValue, reset, formState: { errors }, control } = useForm<ValidationSchema>({
resolver: zodResolver(validationSchema),
defaultValues: {
triggerType: TriggerType.Monthy,
Expand All @@ -48,16 +50,33 @@ export function useNotificationView({ contactId }: UseNotificationViewProps) {
const api = new NotificationTriggersApi();
setIsLoading(true);

await api.register({
contactId: contactId,
templateMessageId: data.templateMessageId,
day: (data.triggerType === TriggerType.Monthy || data.triggerType === TriggerType.Yearly) && data.day ? data.day : null,
month: (data.triggerType === TriggerType.Yearly) && data.month ? data.month : null,
type: data.triggerType,
paramsValue: data.messageTemplateParams
});
if (triggerId) {

await api.update({
triggerId: triggerId,
contactId: contactId,
templateMessageId: data.templateMessageId,
day: (data.triggerType === TriggerType.Monthy || data.triggerType === TriggerType.Yearly) && data.day ? data.day : null,
month: (data.triggerType === TriggerType.Yearly) && data.month ? data.month : null,
type: data.triggerType,
paramsValue: data.messageTemplateParams
});

AppToast.success('Notificação atualizada');

} else {

await api.register({
contactId: contactId,
templateMessageId: data.templateMessageId,
day: (data.triggerType === TriggerType.Monthy || data.triggerType === TriggerType.Yearly) && data.day ? data.day : null,
month: (data.triggerType === TriggerType.Yearly) && data.month ? data.month : null,
type: data.triggerType,
paramsValue: data.messageTemplateParams
});

AppToast.success('Notificação agendada');
AppToast.success('Notificação agendada');
}

router.back();
}
Expand All @@ -71,6 +90,36 @@ export function useNotificationView({ contactId }: UseNotificationViewProps) {
}
};

useEffect(() => {

if (triggerId) return;

setIsLoaded(true);
}, []);

useEffect(() => {

if (!triggerId || messageTemplates.length === 0) return;

(async() => {

const api = new NotificationTriggersApi();
const trigger = await api.getById({ id: triggerId });

reset({
day: trigger.day ?? undefined,
month: trigger.month ?? undefined,
triggerType: trigger.type as any,
templateMessageId: trigger.templateMessage?.id,
messageTemplateParams: trigger.paramsValue
});

setIsLoaded(true);

})();

}, [ triggerId, messageTemplates ]);

useEffect(() => {

if (!messageTemplatedSelected) return;
Expand Down Expand Up @@ -112,6 +161,7 @@ export function useNotificationView({ contactId }: UseNotificationViewProps) {
register,
isLoadingMessageTemplates,
isSaving,
isLoaded,
values,
errors,
control,
Expand Down
Loading

0 comments on commit a95015d

Please sign in to comment.