[offers][feat] integrate isSaved API (#475)

pull/476/head
Zhang Ziqing 2 years ago committed by GitHub
parent 0f1e46bd7e
commit 8798958f3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,3 +1,4 @@
import { signIn, useSession } from 'next-auth/react';
import { useState } from 'react';
import { DocumentDuplicateIcon } from '@heroicons/react/20/solid';
import { BookmarkSquareIcon, CheckIcon } from '@heroicons/react/24/outline';
@ -20,6 +21,7 @@ export default function OffersProfileSave({
const { showToast } = useToast();
const { event: gaEvent } = useGoogleAnalytics();
const [isSaved, setSaved] = useState(false);
const { data: session, status } = useSession();
const saveMutation = trpc.useMutation(
['offers.user.profile.addToUserProfile'],
@ -32,7 +34,10 @@ export default function OffersProfileSave({
});
},
onSuccess: () => {
setSaved(true);
trpcContext.invalidateQueries([
'offers.profile.isSaved',
{ profileId, userId: session?.user?.id },
]);
showToast({
title: `Saved to your dashboard!`,
variant: 'success',
@ -41,16 +46,30 @@ export default function OffersProfileSave({
},
);
const isSavedQuery = trpc.useQuery(
[`offers.profile.isSaved`, { profileId, userId: session?.user?.id }],
{
onSuccess: (res) => {
setSaved(res);
},
},
);
const trpcContext = trpc.useContext();
const handleSave = () => {
saveMutation.mutate({
profileId,
token: token as string,
});
gaEvent({
action: 'offers.profile_submission_save_to_profile',
category: 'engagement',
label: 'Save to profile in profile submission',
});
if (status === 'unauthenticated') {
signIn();
} else {
saveMutation.mutate({
profileId,
token: token as string,
});
gaEvent({
action: 'offers.profile_submission_save_to_profile',
category: 'engagement',
label: 'Save to profile in profile submission',
});
}
};
return (
@ -99,9 +118,9 @@ export default function OffersProfileSave({
</p>
<div className="mb-20">
<Button
disabled={isSaved}
disabled={isSavedQuery.isLoading || isSaved}
icon={isSaved ? CheckIcon : BookmarkSquareIcon}
isLoading={saveMutation.isLoading}
isLoading={saveMutation.isLoading || isSavedQuery.isLoading}
label={isSaved ? 'Saved to user profile' : 'Save to user profile'}
variant="primary"
onClick={handleSave}

@ -1,4 +1,5 @@
import { useRouter } from 'next/router';
import { signIn, useSession } from 'next-auth/react';
import { useState } from 'react';
import {
BookmarkIcon as BookmarkIconOutline,
@ -10,23 +11,22 @@ import {
import { BookmarkIcon as BookmarkIconSolid } from '@heroicons/react/24/solid';
import { Button, Dialog, Spinner, Tabs, useToast } from '@tih/ui';
import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
import type { ProfileDetailTab } from '~/components/offers/constants';
import { profileDetailTabs } from '~/components/offers/constants';
import ProfilePhotoHolder from '~/components/offers/profile/ProfilePhotoHolder';
import type { BackgroundDisplayData } from '~/components/offers/types';
import { JobTypeLabel } from '~/components/offers/types';
import Tooltip from '~/components/offers/util/Tooltip';
import { getProfileEditPath } from '~/utils/offers/link';
import { trpc } from '~/utils/trpc';
import type { ProfileDetailTab } from '../constants';
import { profileDetailTabs } from '../constants';
import Tooltip from '../util/Tooltip';
type ProfileHeaderProps = Readonly<{
background?: BackgroundDisplayData;
handleDelete: () => void;
isEditable: boolean;
isLoading: boolean;
isSaved?: boolean;
selectedTab: ProfileDetailTab;
setSelectedTab: (tab: ProfileDetailTab) => void;
}>;
@ -36,20 +36,41 @@ export default function ProfileHeader({
handleDelete,
isEditable,
isLoading,
isSaved = false,
selectedTab,
setSelectedTab,
}: ProfileHeaderProps) {
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [saved, setSaved] = useState(isSaved);
const [saved, setSaved] = useState(false);
const router = useRouter();
const trpcContext = trpc.useContext();
const { offerProfileId = '', token = '' } = router.query;
const { showToast } = useToast();
const { data: session, status } = useSession();
const { event: gaEvent } = useGoogleAnalytics();
const handleEditClick = () => {
gaEvent({
action: 'offers.edit_profile',
category: 'engagement',
label: 'Edit profile',
});
router.push(getProfileEditPath(offerProfileId as string, token as string));
};
const isSavedQuery = trpc.useQuery(
[
`offers.profile.isSaved`,
{ profileId: offerProfileId as string, userId: session?.user?.id },
],
{
onSuccess: (res) => {
setSaved(res);
},
},
);
const saveMutation = trpc.useMutation(
['offers.user.profile.addToUserProfile'],
{
@ -61,7 +82,13 @@ export default function ProfileHeader({
});
},
onSuccess: () => {
setSaved(true);
trpcContext.invalidateQueries([
'offers.profile.isSaved',
{
profileId: offerProfileId as string,
userId: session?.user?.id,
},
]);
showToast({
title: `Saved to dashboard!`,
variant: 'success',
@ -80,18 +107,25 @@ export default function ProfileHeader({
});
},
onSuccess: () => {
setSaved(false);
trpcContext.invalidateQueries([
'offers.profile.isSaved',
{
profileId: offerProfileId as string,
userId: session?.user?.id,
},
]);
showToast({
title: `Removed from dashboard!`,
variant: 'success',
});
trpcContext.invalidateQueries(['offers.profile.listOne']);
},
},
);
const toggleSaved = () => {
if (saved) {
if (status === 'unauthenticated') {
signIn();
} else if (saved) {
unsaveMutation.mutate({ profileId: offerProfileId as string });
} else {
saveMutation.mutate({
@ -106,15 +140,22 @@ export default function ProfileHeader({
<div className="flex justify-center space-x-2">
<Tooltip
tooltipContent={
isSaved ? 'Remove from account' : 'Save to your account'
saved ? 'Remove from account' : 'Save to your account'
}>
<Button
disabled={
isLoading || saveMutation.isLoading || unsaveMutation.isLoading
isLoading ||
saveMutation.isLoading ||
unsaveMutation.isLoading ||
isSavedQuery.isLoading
}
icon={saved ? BookmarkIconSolid : BookmarkIconOutline}
isLabelHidden={true}
isLoading={saveMutation.isLoading || unsaveMutation.isLoading}
isLoading={
isSavedQuery.isLoading ||
saveMutation.isLoading ||
unsaveMutation.isLoading
}
label={saved ? 'Remove from account' : 'Save to your account'}
size="md"
variant="tertiary"

@ -4,6 +4,7 @@ import { useSession } from 'next-auth/react';
import { useState } from 'react';
import { Spinner, useToast } from '@tih/ui';
import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
import { ProfileDetailTab } from '~/components/offers/constants';
import ProfileComments from '~/components/offers/profile/ProfileComments';
import ProfileDetails from '~/components/offers/profile/ProfileDetails';
@ -36,6 +37,7 @@ export default function OfferProfile() {
);
const [analysis, setAnalysis] = useState<ProfileAnalysis>();
const { data: session } = useSession();
const { event: gaEvent } = useGoogleAnalytics();
const getProfileQuery = trpc.useQuery(
[
@ -176,6 +178,11 @@ export default function OfferProfile() {
profileId: offerProfileId as string,
token: token as string,
});
gaEvent({
action: 'offers.delete_profile',
category: 'engagement',
label: 'Delete profile',
});
}
}
@ -202,7 +209,6 @@ export default function OfferProfile() {
handleDelete={handleDelete}
isEditable={isEditable}
isLoading={getProfileQuery.isLoading}
isSaved={getProfileQuery.data?.isSaved}
selectedTab={selectedTab}
setSelectedTab={setSelectedTab}
/>

@ -1,5 +1,6 @@
import crypto from 'crypto';
import { z } from 'zod';
import type { OffersProfile } from '@prisma/client';
import { JobType } from '@prisma/client';
import * as trpc from '@trpc/server';
@ -108,14 +109,15 @@ export const offersProfileRouter = createRouter()
token: z.string(),
}),
async resolve({ ctx, input }) {
const profile = await ctx.prisma.offersProfile.findFirst({
where: {
id: input.profileId
}
})
const profile: OffersProfile | null =
await ctx.prisma.offersProfile.findFirst({
where: {
id: input.profileId,
},
});
return profile?.editToken === input.token
}
return profile?.editToken === input.token;
},
})
.query('isSaved', {
input: z.object({
@ -123,36 +125,35 @@ export const offersProfileRouter = createRouter()
userId: z.string().nullish(),
}),
async resolve({ ctx, input }) {
if (!input.userId) {
return false
return false;
}
const profile = await ctx.prisma.offersProfile.findFirst({
include: {
users: true
users: true,
},
where: {
id: input.profileId
}
})
id: input.profileId,
},
});
const users = profile?.users
const users = profile?.users;
if (!users) {
return false
return false;
}
let isSaved = false
let isSaved = false;
for (let i = 0; i < users.length; i++) {
if (users[i].id === input.userId) {
isSaved = true
isSaved = true;
}
}
return isSaved
}
return isSaved;
},
})
.query('listOne', {
input: z.object({

Loading…
Cancel
Save