Skip to content

Commit 0bea2aa

Browse files
authored
Merge pull request #3221 from dubinc/partner-onboarding-image
Make partner onboarding image optional and sync to user
2 parents 4b5c1d2 + e914ee2 commit 0bea2aa

File tree

3 files changed

+48
-40
lines changed

3 files changed

+48
-40
lines changed

apps/web/app/(ee)/partners.dub.co/(onboarding)/onboarding/onboarding-form.tsx

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
"use client";
22

3+
import { parseActionError } from "@/lib/actions/parse-action-errors";
34
import { PartnerData } from "@/lib/actions/partners/create-program-application";
45
import { onboardPartnerAction } from "@/lib/actions/partners/onboard-partner";
56
import { onboardPartnerSchema } from "@/lib/zod/schemas/partners";
67
import { CountryCombobox } from "@/ui/partners/country-combobox";
78
import { Partner } from "@dub/prisma/client";
89
import {
910
Button,
10-
buttonVariants,
1111
FileUpload,
1212
ToggleGroup,
1313
TooltipContent,
1414
useEnterSubmit,
1515
useLocalStorage,
1616
useMediaQuery,
1717
} from "@dub/ui";
18-
import { cn } from "@dub/utils/src/functions";
18+
import { cn } from "@dub/utils";
1919
import { AnimatePresence, LayoutGroup, motion } from "motion/react";
2020
import { useSession } from "next-auth/react";
2121
import { useAction } from "next-safe-action/hooks";
@@ -96,7 +96,7 @@ export function OnboardingForm({
9696
router.push("/onboarding/platforms");
9797
},
9898
onError: ({ error, input }) => {
99-
toast.error(error.serverError);
99+
toast.error(parseActionError(error, "An unknown error occurred."));
100100
reset(input);
101101
},
102102
});
@@ -111,7 +111,7 @@ export function OnboardingForm({
111111
className="flex w-full flex-col gap-6 text-left"
112112
>
113113
<label>
114-
<span className="text-sm font-medium text-neutral-800">Full Name</span>
114+
<span className="text-sm font-medium text-neutral-800">Name</span>
115115
<input
116116
type="text"
117117
className={cn(
@@ -129,22 +129,18 @@ export function OnboardingForm({
129129

130130
<label>
131131
<span className="text-sm font-medium text-neutral-800">
132-
Profile Image
132+
Profile image
133133
</span>
134134
<div className="flex items-center gap-5">
135135
<Controller
136136
control={control}
137137
name="image"
138-
rules={{ required: true }}
139138
render={({ field }) => (
140139
<FileUpload
141140
accept="images"
142-
className={cn(
143-
"mt-1.5 size-20 rounded-full border border-neutral-300",
144-
errors.image && "border-0 ring-2 ring-red-500",
145-
)}
141+
className="mt-1.5 size-20 rounded-full border border-neutral-300"
146142
iconClassName="size-5"
147-
previewClassName="size-10 rounded-full"
143+
previewClassName="size-20 rounded-full"
148144
variant="plain"
149145
imageSrc={field.value}
150146
readFile
@@ -156,16 +152,11 @@ export function OnboardingForm({
156152
)}
157153
/>
158154
<div>
159-
<div
160-
className={cn(
161-
buttonVariants({ variant: "secondary" }),
162-
"flex h-7 w-fit cursor-pointer items-center rounded-md border px-2 text-xs",
163-
)}
164-
>
165-
Upload image
166-
</div>
167-
<p className="mt-1.5 text-xs text-neutral-500">
168-
Recommended size: 160x160px
155+
<p className="text-xs text-neutral-500">
156+
Square image recommended, up to 2 MB.
157+
</p>
158+
<p className="mt-0.5 text-xs font-medium text-neutral-500">
159+
Adding an image can improve your approval rates.
169160
</p>
170161
</div>
171162
</div>

apps/web/lib/actions/partners/onboard-partner.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ export const onboardPartnerAction = authUserActionClient
2929
? existingPartner.id
3030
: createId({ prefix: "pn_" });
3131

32-
const imageUrl = await storage
33-
.upload({
34-
key: `partners/${partnerId}/image_${nanoid(7)}`,
35-
body: image,
36-
})
37-
.then(({ url }) => url);
32+
const imageUrl = image
33+
? await storage
34+
.upload({
35+
key: `partners/${partnerId}/image_${nanoid(7)}`,
36+
body: image,
37+
})
38+
.then(({ url }) => url)
39+
: undefined;
3840

3941
// country, profileType, and companyName cannot be changed once set
4042
const payload: Prisma.PartnerCreateInput = {
@@ -79,8 +81,8 @@ export const onboardPartnerAction = authUserActionClient
7981
},
8082
}),
8183

82-
// only set the default partner ID if the user doesn't already have one
83-
!user.defaultPartnerId &&
84+
// if the user doesn't have a default partner id, set the new partner id as the user's default partner id
85+
user.defaultPartnerId &&
8486
prisma.user.update({
8587
where: {
8688
id: user.id,
@@ -93,4 +95,23 @@ export const onboardPartnerAction = authUserActionClient
9395

9496
// Complete any outstanding program application
9597
waitUntil(completeProgramApplications(user.email));
98+
99+
// if the user doesn't have an image, set the uploaded image as the user's image
100+
if (!user.image && image) {
101+
waitUntil(
102+
storage
103+
.upload({
104+
key: `avatars/${user.id}`,
105+
body: image,
106+
})
107+
.then(({ url }) => {
108+
prisma.user.update({
109+
where: {
110+
id: user.id,
111+
},
112+
data: { image: url },
113+
});
114+
}),
115+
);
116+
}
96117
});

apps/web/lib/zod/schemas/partners.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -601,17 +601,13 @@ export const createPartnerSchema = z.object({
601601

602602
// This is a temporary fix to allow arbitrary image URL
603603
// TODO: Fix this by using file-type
604-
const partnerImageSchema = z
605-
.union([
606-
base64ImageSchema,
607-
storedR2ImageUrlSchema,
608-
publicHostedImageSchema,
609-
googleFaviconUrlSchema,
610-
])
611-
.transform((v) => v || "")
612-
.refine((v) => v !== "", {
613-
message: "Image is required",
614-
});
604+
const partnerImageSchema = z.union([
605+
base64ImageSchema,
606+
storedR2ImageUrlSchema,
607+
publicHostedImageSchema,
608+
googleFaviconUrlSchema,
609+
z.string().nullish(), // make image optional
610+
]);
615611

616612
export const onboardPartnerSchema = createPartnerSchema
617613
.omit({

0 commit comments

Comments
 (0)