Skip to content

Commit

Permalink
Implement referral source for onboarding
Browse files Browse the repository at this point in the history
  • Loading branch information
sanjana-singhania committed Jan 25, 2025
1 parent 34bd366 commit 8c9d2b2
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 53 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@ import { z } from "zod";
import { zPreProcessEmptyString } from "@good-dog/trpc/utils";

import RegistrationInput from "../inputs/RegistrationInput";
import DiscoveryDropdown from "./DiscoveryDropdown";
import OnboardingFormProvider from "./OnboardingFormProvider";
import ReferralDropdown from "./ReferralDropdown";
import { ReferralSource } from ".prisma/client";

const Schema = z.object({
role: z.literal("MEDIA_MAKER"),
firstName: zPreProcessEmptyString(z.string()),
lastName: zPreProcessEmptyString(z.string()),
discovery: z.string().optional(),
referral: z
.object({
source: z.nativeEnum(ReferralSource),
customSource: zPreProcessEmptyString(z.string().optional()),
})
.optional(),
});

type FormValues = z.infer<typeof Schema>;
Expand Down Expand Up @@ -51,7 +57,7 @@ export default function MediaMakerForm(
label="Last Name"
/>
</div>
<DiscoveryDropdown />
<ReferralDropdown />
</OnboardingFormProvider>
);
}
12 changes: 9 additions & 3 deletions packages/components/src/registration/onboarding/MusicianForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
import { useFieldArray, useFormContext } from "react-hook-form";
import { z } from "zod";

import { ReferralSource } from "@good-dog/db";
import { zPreProcessEmptyString } from "@good-dog/trpc/utils";
import { Button } from "@good-dog/ui/button";

import RegistrationCheckbox from "../inputs/RegistrationCheckbox";
import RegistrationInput from "../inputs/RegistrationInput";
import DiscoveryDropdown from "./DiscoveryDropdown";
import OnboardingFormProvider from "./OnboardingFormProvider";
import ReferralDropdown from "./ReferralDropdown";

const Schema = z.object({
role: z.literal("MUSICIAN"),
Expand All @@ -33,7 +34,12 @@ const Schema = z.object({
}),
)
.optional(),
discovery: z.string().optional(),
referral: z
.object({
source: z.nativeEnum(ReferralSource),
customSource: zPreProcessEmptyString(z.string().optional()),
})
.optional(),
});

type FormValues = z.infer<typeof Schema>;
Expand Down Expand Up @@ -103,7 +109,7 @@ export default function MusicianForm(
</div>
<hr className="mx-auto my-6 w-full border-good-dog-violet" />
<GroupMemberForm />
<DiscoveryDropdown />
<ReferralDropdown />
</OnboardingFormProvider>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ import { useRouter } from "next/navigation";
import { zodResolver } from "@hookform/resolvers/zod";
import { FormProvider, useForm } from "react-hook-form";

import type { ReferralType } from "@good-dog/db";
import { trpc } from "@good-dog/trpc/client";
import { Button } from "@good-dog/ui/button";

interface BaseValues {
role: "MEDIA_MAKER" | "MUSICIAN";
firstName: string;
lastName: string;
discovery?: string;
referral?: {
source: ReferralType;
customSource?: string;
};
}

export default function OnboardingFormProvider<
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form";

import { ReferralSource } from "@good-dog/db";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@good-dog/ui/select";

export default function ReferralDropdown() {
const { control, register } = useFormContext<{
source?: string;
customSource?: string;
}>();

const referralOptions = Object.values(ReferralSource);

const [isOtherSelected, setIsOtherSelected] = useState(false);

const handleSelectChange = (value: string) => {
setIsOtherSelected(value === "OTHER");
};

return (
<div>
<h3 className="mb-3 mt-4">How did you hear about Good Dog?</h3>
<Controller
name="source"
control={control}
render={({ field }) => (
<Select
{...field}
onValueChange={(value: string) => {
field.onChange(value);
handleSelectChange(value);
}}
>
<SelectTrigger className="border-black bg-white">
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{referralOptions.map((option) => (
<SelectItem key={option} value={option}>
{option}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
)}
/>

{isOtherSelected && (
<div className="mt-4">
<label htmlFor="customSource" className="mb-2 block">
Please specify:
</label>
<input
id="customSource"
{...register("customSource")}
type="text"
placeholder="Enter details"
className="w-full border border-black p-2"
/>
</div>
)}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- CreateEnum
CREATE TYPE "ReferralSource" AS ENUM ('FRIEND', 'COLLEAGUE', 'GREEN_LINE_RECORDS', 'SOCIAL_MEDIA', 'OTHER');

-- CreateTable
CREATE TABLE "Referral" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"source" "ReferralSource" NOT NULL,
"customSource" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "Referral_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "Referral_userId_key" ON "Referral"("userId");

-- AddForeignKey
ALTER TABLE "Referral" ADD CONSTRAINT "Referral_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
19 changes: 19 additions & 0 deletions packages/db/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,29 @@ model User {
passwordResetReq PasswordResetReq?
sessions Session[]
sentInvites GroupInvite[]
referral Referral?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model Referral {
id String @id @default(uuid())
user User @relation(fields: [userId], references: [userId])
userId String @unique
source ReferralSource
customSource String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

enum ReferralSource {
FRIEND
COLLEAGUE
GREEN_LINE_RECORDS
SOCIAL_MEDIA
OTHER
}

model Session {
sessionId String @id @default(uuid()) @map("id")
userId String
Expand Down
5 changes: 4 additions & 1 deletion packages/db/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { PrismaClient } from "@prisma/client";
import { PrismaClient, ReferralSource } from "@prisma/client";

export const prisma = new PrismaClient();

export { ReferralSource };
export type ReferralType = keyof typeof ReferralSource;
24 changes: 22 additions & 2 deletions packages/trpc/src/procedures/onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { revalidatePath } from "next/cache";
import { TRPCError } from "@trpc/server";
import { z } from "zod";

import { ReferralSource } from "@good-dog/db";

import { authenticatedProcedureBuilder } from "../internal/init";
import { zPreProcessEmptyString } from "../utils";

Expand All @@ -12,12 +14,23 @@ export const onboardingProcedure = authenticatedProcedureBuilder
role: z.literal("MEDIA_MAKER"),
firstName: z.string(),
lastName: z.string(),
discovery: z.string().optional(),
referral: z
.object({
source: z.nativeEnum(ReferralSource),
customSource: zPreProcessEmptyString(z.string().optional()),
})
.optional(),
}),
z.object({
role: z.literal("MUSICIAN"),
firstName: zPreProcessEmptyString(z.string()),
lastName: zPreProcessEmptyString(z.string()),
referral: z
.object({
source: z.nativeEnum(ReferralSource),
customSource: zPreProcessEmptyString(z.string().optional()),
})
.optional(),
groupName: zPreProcessEmptyString(z.string()),
stageName: zPreProcessEmptyString(z.string().optional()),
isSongWriter: z.boolean().optional(),
Expand All @@ -36,7 +49,6 @@ export const onboardingProcedure = authenticatedProcedureBuilder
}),
)
.optional(),
discovery: z.string().optional(),
}),
]),
)
Expand Down Expand Up @@ -66,6 +78,14 @@ export const onboardingProcedure = authenticatedProcedureBuilder
role: "MUSICIAN",
firstName: input.firstName,
lastName: input.lastName,
referral: input.referral
? {
create: {
source: input.referral.source,
customSource: input.referral.customSource,
},
}
: undefined,
stageName: input.stageName,
isSongWriter: input.isSongWriter,
isAscapAffiliated: input.isAscapAffiliated,
Expand Down

0 comments on commit 8c9d2b2

Please sign in to comment.