Skip to content

Commit

Permalink
feat(subscriber): Implement patch subscriber functionality and update…
Browse files Browse the repository at this point in the history
… UI components
  • Loading branch information
BiswaViraj committed Jan 31, 2025
1 parent 8c083f7 commit 4d24095
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 10 deletions.
27 changes: 25 additions & 2 deletions apps/dashboard/src/api/subscribers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import type { DirectionEnum, IEnvironment, IGetSubscriberResponseDto, IListSubscribersResponseDto } from '@novu/shared';
import { getV2 } from './api.client';
import type {
DirectionEnum,
IEnvironment,
IGetSubscriberResponseDto,
IListSubscribersResponseDto,
IPatchSubscriberRequestDto,
} from '@novu/shared';
import { getV2, patchV2 } from './api.client';

export const getSubscribers = async ({
environment,
Expand Down Expand Up @@ -56,3 +62,20 @@ export const getSubscriber = async ({

return data;
};

export const patchSubscriber = async ({
environment,
subscriberId,
subscriber,
}: {
environment: IEnvironment;
subscriberId: string;
subscriber: Partial<IPatchSubscriberRequestDto>;
}) => {
const { data } = await patchV2<{ data: IGetSubscriberResponseDto }>(`/subscribers/${subscriberId}`, {
environment,
body: subscriber,
});

return data;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { VisuallyHidden } from '../primitives/visually-hidden';
import { useNavigate } from 'react-router-dom';
import { PropsWithChildren } from 'react';

const transitionSetting = { ease: [0.29, 0.83, 0.57, 0.99], duration: 0.4 };
const transitionSetting = { duration: 0.4 };

type SubscriberDrawerProps = PropsWithChildren<{
open: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,55 @@ import { TimezoneSelect } from './timezone-select';
import { Avatar, AvatarFallback, AvatarImage } from '../primitives/avatar';
import { Tooltip, TooltipContent, TooltipTrigger } from '../primitives/tooltip';
import { Link } from 'react-router-dom';
import { usePatchSubscriber } from '@/hooks/use-patch-subscriber';
import { showSuccessToast } from '../primitives/sonner-helpers';

const extensions = [loadLanguage('json')?.extension ?? []];
const basicSetup = { lineNumbers: true, defaultKeymap: true };

export default function SubscriberOverviewForm({ subscriberId }: { subscriberId: string }) {
const { data } = useFetchSubscriber({ subscriberId });
const { patchSubscriber } = usePatchSubscriber({
onSuccess: () => {
showSuccessToast('Subscriber updated successfully');
},
});

const form = useForm<z.infer<typeof SubscriberFormSchema>>({
values: { ...data, data: JSON.stringify(data?.data, null, 2) },
resolver: zodResolver(SubscriberFormSchema),
shouldFocusError: false,
});

const onSubmit = (data: z.infer<typeof SubscriberFormSchema>) => {
console.log(data);
const onSubmit = async (formData: z.infer<typeof SubscriberFormSchema>) => {
const dirtyFields = form.formState.dirtyFields;

const dirtyPayload = Object.keys(dirtyFields).reduce<Partial<typeof formData>>((acc, key) => {
const typedKey = key as keyof typeof formData;
if (typedKey === 'data') {
return { ...acc, data: JSON.parse(formData.data) };
}
return { ...acc, [typedKey]: formData[typedKey] };
}, {});

if (!Object.keys(dirtyPayload).length) {
return;
}

await patchSubscriber({ subscriberId, subscriber: dirtyPayload });
};

return (
<div className="flex h-full flex-col items-stretch">
<Form {...form}>
<form autoComplete="off" noValidate onSubmit={form.handleSubmit(onSubmit)} className="flex h-full flex-col">
<form
autoComplete="off"
noValidate
onSubmit={form.handleSubmit(onSubmit, (err) => {
console.log({ err });
})}
className="flex h-full flex-col"
>
<div className="flex flex-col items-stretch gap-6 p-5">
<div className="flex items-center gap-3">
<Tooltip>
Expand Down Expand Up @@ -244,7 +272,13 @@ export default function SubscriberOverviewForm({ subscriberId }: { subscriberId:
<Button type="submit" variant="primary" mode="ghost" leadingIcon={RiDeleteBin2Line}>
Delete subscriber
</Button>
<Button variant="secondary">Save changes</Button>
<Button
variant="secondary"
type="submit"
disabled={!form.formState.isDirty || Object.keys(form.formState.dirtyFields).length === 0}
>
Save changes
</Button>
</div>
</div>
</form>
Expand Down
4 changes: 2 additions & 2 deletions apps/dashboard/src/components/subscribers/subscriber-tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import SubscriberOverviewForm from './subscriber-overview-form';
const tabTriggerClasses =
' hover:data-[state=inactive]:text-foreground-950 h-11 data-[state=active]:border-b data-[state=active]:border-primary-base data-[state=active]:border-b-2 py-3 rounded-none [&>span]:h-5 px-0';

export default function SubscriberTabs() {
export default function SubscriberTabs({ subscriberId }: { subscriberId: string }) {
const navigate = useNavigate();

return (
Expand Down Expand Up @@ -47,7 +47,7 @@ export default function SubscriberTabs() {
</TabsTrigger>
</TabsList>
<TabsContent value="overview" className="h-full w-full overflow-y-auto">
<SubscriberOverviewForm subscriberId="test" />
<SubscriberOverviewForm subscriberId={subscriberId} />
</TabsContent>
<TabsContent value="credentials" className="h-full w-full overflow-y-auto">
<h2>Credentials</h2>
Expand Down
36 changes: 36 additions & 0 deletions apps/dashboard/src/hooks/use-patch-subscriber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { patchSubscriber } from '@/api/subscribers';
import { useEnvironment } from '@/context/environment/hooks';
import { QueryKeys } from '@/utils/query-keys';
import { OmitEnvironmentFromParameters } from '@/utils/types';
import type { IGetSubscriberResponseDto } from '@novu/shared';
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';

type PatchSubscriberParameters = OmitEnvironmentFromParameters<typeof patchSubscriber>;

export const usePatchSubscriber = (
options?: UseMutationOptions<IGetSubscriberResponseDto, unknown, PatchSubscriberParameters>
) => {
const queryClient = useQueryClient();
const { currentEnvironment } = useEnvironment();

const { mutateAsync, ...rest } = useMutation({
mutationFn: (args: PatchSubscriberParameters) => patchSubscriber({ environment: currentEnvironment!, ...args }),
...options,
onSuccess: async (data, variables, ctx) => {
await queryClient.invalidateQueries({
queryKey: [QueryKeys.fetchSubscribers],
});

await queryClient.invalidateQueries({
queryKey: [QueryKeys.fetchSubscriber],
});

options?.onSuccess?.(data, variables, ctx);
},
});

return {
...rest,
patchSubscriber: mutateAsync,
};
};
9 changes: 8 additions & 1 deletion apps/dashboard/src/pages/edit-subscriber-page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { SubscriberDrawer } from '@/components/subscribers/subscriber-drawer';
import SubscriberTabs from '@/components/subscribers/subscriber-tabs';
import { useParams } from 'react-router-dom';

export function EditSubscriberPage() {
const { subscriberId } = useParams<{ subscriberId: string }>();

if (!subscriberId) {
return null;
}

return (
<SubscriberDrawer open>
<SubscriberTabs />
<SubscriberTabs subscriberId={subscriberId} />
</SubscriberDrawer>
);
}

0 comments on commit 4d24095

Please sign in to comment.