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
6 changes: 5 additions & 1 deletion apps/web/core/components/onboarding/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ export const OnboardingHeader = observer(function OnboardingHeader(props: Onboar
// derived values
const currentStepNumber = getCurrentStepNumber();
const totalSteps = hasInvitations ? 4 : 5; // 4 if invites available, 5 if not
const userName = user?.display_name ?? `${user?.first_name} ${user?.last_name}` ?? user?.email;
const userName = user?.display_name
? user?.display_name
: user?.first_name
? `${user?.first_name} ${user?.last_name ?? ""}`
: user?.email;

return (
<div className="flex flex-col gap-4 sticky top-0 z-10">
Expand Down
61 changes: 38 additions & 23 deletions apps/web/core/components/onboarding/profile-setup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type { IUser, TUserProfile, TOnboardingSteps } from "@plane/types";
// ui
import { Input, PasswordStrengthIndicator, Spinner } from "@plane/ui";
// components
import { getFileURL, getPasswordStrength } from "@plane/utils";
import { cn, getFileURL, getPasswordStrength } from "@plane/utils";
import { UserImageUploadModal } from "@/components/core/modals/user-image-upload-modal";
// constants
// helpers
Expand All @@ -33,7 +33,7 @@ type TProfileSetupFormValues = {
password?: string;
confirm_password?: string;
role?: string;
use_case?: string;
use_case?: string[];
};

const defaultValues: Partial<TProfileSetupFormValues> = {
Expand All @@ -43,7 +43,7 @@ const defaultValues: Partial<TProfileSetupFormValues> = {
password: undefined,
confirm_password: undefined,
role: undefined,
use_case: undefined,
use_case: [],
};

type Props = {
Expand Down Expand Up @@ -139,7 +139,7 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
avatar_url: formData.avatar_url ?? undefined,
};
const profileUpdatePayload: Partial<TUserProfile> = {
use_case: formData.use_case,
use_case: formData.use_case && formData.use_case.length > 0 ? formData.use_case.join(". ") : undefined,
role: formData.role,
};
try {
Expand All @@ -151,7 +151,7 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
captureSuccess({
eventName: USER_TRACKER_EVENTS.add_details,
payload: {
use_case: formData.use_case,
use_case: profileUpdatePayload.use_case,
role: formData.role,
},
});
Expand Down Expand Up @@ -212,7 +212,7 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {

const handleSubmitUserPersonalization = async (formData: TProfileSetupFormValues) => {
const profileUpdatePayload: Partial<TUserProfile> = {
use_case: formData.use_case,
use_case: formData.use_case && formData.use_case.length > 0 ? formData.use_case.join(". ") : undefined,
role: formData.role,
};
try {
Expand All @@ -223,7 +223,7 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
captureSuccess({
eventName: USER_TRACKER_EVENTS.add_details,
payload: {
use_case: formData.use_case,
use_case: profileUpdatePayload.use_case,
role: formData.role,
},
});
Expand Down Expand Up @@ -519,9 +519,13 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
{USER_ROLE.map((userRole) => (
<div
key={userRole}
className={`flex-shrink-0 border-[0.5px] hover:cursor-pointer hover:bg-custom-background-90 ${
value === userRole ? "border-custom-primary-100" : "border-custom-border-300"
} rounded px-3 py-1.5 text-sm font-medium`}
className={cn(
"flex-shrink-0 border-[0.5px] hover:cursor-pointer hover:bg-custom-background-90 rounded px-3 py-1.5 text-sm font-medium",
{
"border-custom-primary-100": value === userRole,
"border-custom-border-300": value !== userRole,
}
)}
onClick={() => onChange(userRole)}
>
{userRole}
Expand All @@ -537,27 +541,38 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
className="text-sm text-custom-text-300 font-medium after:content-['*'] after:ml-0.5 after:text-red-500"
htmlFor="use_case"
>
What is your domain expertise? Choose one.
What is your domain expertise? Choose one or more.
</label>
<Controller
control={control}
name="use_case"
rules={{
required: "This field is required",
required: "Please select at least one option",
validate: (value) => (value && value.length > 0) || "Please select at least one option",
}}
render={({ field: { value, onChange } }) => (
<div className="flex flex-wrap gap-2 py-2 overflow-auto break-all">
{USER_DOMAIN.map((userDomain) => (
<div
key={userDomain}
className={`flex-shrink-0 border-[0.5px] hover:cursor-pointer hover:bg-custom-background-90 ${
value === userDomain ? "border-custom-primary-100" : "border-custom-border-300"
} rounded px-3 py-1.5 text-sm font-medium`}
onClick={() => onChange(userDomain)}
>
{userDomain}
</div>
))}
{USER_DOMAIN.map((userDomain) => {
const isSelected = value?.includes(userDomain) || false;
return (
<div
key={userDomain}
className={`flex-shrink-0 border-[0.5px] hover:cursor-pointer hover:bg-custom-background-90 ${
isSelected ? "border-custom-primary-100" : "border-custom-border-300"
} rounded px-3 py-1.5 text-sm font-medium`}
onClick={() => {
const currentValue = value || [];
if (isSelected) {
onChange(currentValue.filter((item) => item !== userDomain));
} else {
onChange([...currentValue, userDomain]);
}
}}
>
{userDomain}
</div>
);
})}
</div>
)}
/>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/core/components/onboarding/steps/profile/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export type TProfileSetupFormValues = {
password?: string;
confirm_password?: string;
role?: string;
use_case?: string;
use_case?: string[];
has_marketing_email_consent?: boolean;
};

Expand Down
24 changes: 16 additions & 8 deletions apps/web/core/components/onboarding/steps/usecase/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Props = {
};

const defaultValues = {
use_case: "",
use_case: [] as string[],
};

export const UseCaseSetupStep = observer(function UseCaseSetupStep({ handleStepChange }: Props) {
Expand All @@ -36,15 +36,15 @@ export const UseCaseSetupStep = observer(function UseCaseSetupStep({ handleStepC
} = useForm<TProfileSetupFormValues>({
defaultValues: {
...defaultValues,
use_case: profile?.use_case,
use_case: profile?.use_case ? profile.use_case.split(". ") : [],
},
mode: "onChange",
});

// handle submit
const handleSubmitUserPersonalization = async (formData: TProfileSetupFormValues) => {
const profileUpdatePayload: Partial<TUserProfile> = {
use_case: formData.use_case,
use_case: formData.use_case && formData.use_case.length > 0 ? formData.use_case.join(". ") : undefined,
};
try {
await Promise.all([
Expand All @@ -54,7 +54,7 @@ export const UseCaseSetupStep = observer(function UseCaseSetupStep({ handleStepC
captureSuccess({
eventName: USER_TRACKER_EVENTS.add_details,
payload: {
use_case: formData.use_case,
use_case: profileUpdatePayload.use_case,
},
});
setToast({
Expand Down Expand Up @@ -100,25 +100,33 @@ export const UseCaseSetupStep = observer(function UseCaseSetupStep({ handleStepC

{/* Use Case Selection */}
<div className="flex flex-col gap-3">
<p className="text-sm font-medium text-custom-text-400">Select any</p>
<p className="text-sm font-medium text-custom-text-400">Select one or more</p>

<Controller
control={control}
name="use_case"
rules={{
required: "This field is required",
required: "Please select at least one option",
validate: (value) => (value && value.length > 0) || "Please select at least one option",
}}
render={({ field: { value, onChange } }) => (
<div className="flex flex-col gap-3">
{USE_CASES.map((useCase) => {
const isSelected = value === useCase;
const isSelected = value?.includes(useCase) || false;
return (
<button
key={useCase}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onChange(useCase);
const currentValue = value || [];
if (isSelected) {
// Remove from array
onChange(currentValue.filter((item) => item !== useCase));
} else {
// Add to array
onChange([...currentValue, useCase]);
}
}}
className={`w-full px-3 py-2 rounded-lg border transition-all duration-200 flex items-center gap-2 ${
isSelected
Expand Down
Loading