Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
"use client";

import { parseActionError } from "@/lib/actions/parse-action-errors";
import { PartnerData } from "@/lib/actions/partners/create-program-application";
import { onboardPartnerAction } from "@/lib/actions/partners/onboard-partner";
import { onboardPartnerSchema } from "@/lib/zod/schemas/partners";
import { CountryCombobox } from "@/ui/partners/country-combobox";
import { Partner } from "@dub/prisma/client";
import {
Button,
buttonVariants,
FileUpload,
ToggleGroup,
TooltipContent,
useEnterSubmit,
useLocalStorage,
useMediaQuery,
} from "@dub/ui";
import { cn } from "@dub/utils/src/functions";
import { cn } from "@dub/utils";
import { AnimatePresence, LayoutGroup, motion } from "motion/react";
import { useSession } from "next-auth/react";
import { useAction } from "next-safe-action/hooks";
Expand Down Expand Up @@ -96,7 +96,7 @@ export function OnboardingForm({
router.push("/onboarding/platforms");
},
onError: ({ error, input }) => {
toast.error(error.serverError);
toast.error(parseActionError(error, "An unknown error occurred."));
reset(input);
},
});
Expand All @@ -111,7 +111,7 @@ export function OnboardingForm({
className="flex w-full flex-col gap-6 text-left"
>
<label>
<span className="text-sm font-medium text-neutral-800">Full Name</span>
<span className="text-sm font-medium text-neutral-800">Name</span>
<input
type="text"
className={cn(
Expand All @@ -129,22 +129,18 @@ export function OnboardingForm({

<label>
<span className="text-sm font-medium text-neutral-800">
Profile Image
Profile image
</span>
<div className="flex items-center gap-5">
<Controller
control={control}
name="image"
rules={{ required: true }}
render={({ field }) => (
<FileUpload
accept="images"
className={cn(
"mt-1.5 size-20 rounded-full border border-neutral-300",
errors.image && "border-0 ring-2 ring-red-500",
)}
className="mt-1.5 size-20 rounded-full border border-neutral-300"
iconClassName="size-5"
previewClassName="size-10 rounded-full"
previewClassName="size-20 rounded-full"
variant="plain"
imageSrc={field.value}
readFile
Expand All @@ -156,16 +152,11 @@ export function OnboardingForm({
)}
/>
<div>
<div
className={cn(
buttonVariants({ variant: "secondary" }),
"flex h-7 w-fit cursor-pointer items-center rounded-md border px-2 text-xs",
)}
>
Upload image
</div>
<p className="mt-1.5 text-xs text-neutral-500">
Recommended size: 160x160px
<p className="text-xs text-neutral-500">
Square image recommended, up to 2 MB.
</p>
<p className="mt-0.5 text-xs font-medium text-neutral-500">
Adding an image can improve your approval rates.
</p>
</div>
</div>
Expand Down
37 changes: 29 additions & 8 deletions apps/web/lib/actions/partners/onboard-partner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ export const onboardPartnerAction = authUserActionClient
? existingPartner.id
: createId({ prefix: "pn_" });

const imageUrl = await storage
.upload({
key: `partners/${partnerId}/image_${nanoid(7)}`,
body: image,
})
.then(({ url }) => url);
const imageUrl = image
? await storage
.upload({
key: `partners/${partnerId}/image_${nanoid(7)}`,
body: image,
})
.then(({ url }) => url)
: undefined;

// country, profileType, and companyName cannot be changed once set
const payload: Prisma.PartnerCreateInput = {
Expand Down Expand Up @@ -79,8 +81,8 @@ export const onboardPartnerAction = authUserActionClient
},
}),

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

// Complete any outstanding program application
waitUntil(completeProgramApplications(user.email));

// if the user doesn't have an image, set the uploaded image as the user's image
if (!user.image && image) {
waitUntil(
storage
.upload({
key: `avatars/${user.id}`,
body: image,
})
.then(({ url }) => {
prisma.user.update({
where: {
id: user.id,
},
data: { image: url },
});
}),
);
}
});
18 changes: 7 additions & 11 deletions apps/web/lib/zod/schemas/partners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,17 +601,13 @@ export const createPartnerSchema = z.object({

// This is a temporary fix to allow arbitrary image URL
// TODO: Fix this by using file-type
const partnerImageSchema = z
.union([
base64ImageSchema,
storedR2ImageUrlSchema,
publicHostedImageSchema,
googleFaviconUrlSchema,
])
.transform((v) => v || "")
.refine((v) => v !== "", {
message: "Image is required",
});
const partnerImageSchema = z.union([
base64ImageSchema,
storedR2ImageUrlSchema,
publicHostedImageSchema,
googleFaviconUrlSchema,
z.string().nullish(), // make image optional
]);

export const onboardPartnerSchema = createPartnerSchema
.omit({
Expand Down