feat: onboarding v3 QA final roast (#25667)

* remove leading none

* remove back button if coming from teams/org onboarding

* add skip now
This commit is contained in:
sean-brydon
2025-12-08 11:35:44 +00:00
committed by GitHub
parent c1b7b6e83d
commit fadd824d12
7 changed files with 39 additions and 21 deletions
@@ -19,7 +19,7 @@ export const generateMetadata = async () => {
);
};
const ServerPage = async () => {
const ServerPage = async (props: { searchParams: Promise<{ fromTeamOnboarding?: string }> }) => {
const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) });
if (!session?.user?.id) {
@@ -28,8 +28,10 @@ const ServerPage = async () => {
const userEmail = session.user.email || "";
const userName = session.user.name || "";
const searchParams = await props.searchParams;
const fromTeamOnboarding = searchParams?.fromTeamOnboarding === "true";
return <PersonalSettingsView userEmail={userEmail} userName={userName} />;
return <PersonalSettingsView userEmail={userEmail} userName={userName} fromTeamOnboarding={fromTeamOnboarding} />;
};
export default ServerPage;
@@ -43,6 +43,7 @@ async function getHandler(req: NextRequest) {
// If onboarding-v3 is enabled AND organizationOnboardingId exists, redirect to onboarding flow
if (isOnboardingV3Enabled && organizationOnboardingId) {
params.append("fromTeamOnboarding", "true");
const redirectUrl = new URL(
`/onboarding/personal/settings?${params.toString()}`,
WEBAPP_URL
@@ -105,9 +105,9 @@ export function useCreateTeam() {
// Redirect to personal settings after successful invite
const gettingStartedPath = flags["onboarding-v3"]
? "/onboarding/personal/settings"
? "/onboarding/personal/settings?fromTeamOnboarding=true"
: "/getting-started";
router.push(gettingStartedPath);
router.replace(gettingStartedPath);
} catch (error) {
console.error("Failed to invite members:", error);
// Extract error message from TRPC error
@@ -81,6 +81,11 @@ export const OrganizationBrandView = ({ userEmail }: OrganizationBrandViewProps)
router.push("/onboarding/organization/teams");
};
const handleSkip = () => {
// Skip brand customization and go to teams
router.push("/onboarding/organization/teams");
};
return (
<OnboardingLayout userEmail={userEmail} currentStep={2} totalSteps={4}>
{/* Left column - Main content */}
@@ -95,9 +100,14 @@ export const OrganizationBrandView = ({ userEmail }: OrganizationBrandViewProps)
onClick={() => router.push("/onboarding/organization/details")}>
{t("back")}
</Button>
<Button color="primary" className="rounded-[10px]" onClick={handleContinue}>
{t("continue")}
</Button>
<div className="flex items-center gap-2">
<Button color="minimal" className="rounded-[10px]" onClick={handleSkip}>
{t("onboarding_skip_for_now")}
</Button>
<Button color="primary" className="rounded-[10px]" onClick={handleContinue}>
{t("continue")}
</Button>
</div>
</div>
}>
{/* Form */}
@@ -37,9 +37,7 @@ export const InstallableAppCard = ({
</span>
)}
{app.logo && <img src={app.logo} alt={app.name} className="h-9 w-9 rounded-md" />}
<p
className="text-default line-clamp-1 break-words text-left text-sm font-medium leading-none"
title={app.name}>
<p className="text-default line-clamp-1 break-words text-left text-sm font-medium" title={app.name}>
{app.name}
</p>
<InstallAppButtonWithoutPlanCheck
@@ -26,9 +26,14 @@ import { useOnboardingStore } from "../../store/onboarding-store";
type PersonalSettingsViewProps = {
userEmail: string;
userName?: string;
fromTeamOnboarding?: boolean;
};
export const PersonalSettingsView = ({ userEmail, userName }: PersonalSettingsViewProps) => {
export const PersonalSettingsView = ({
userEmail,
userName,
fromTeamOnboarding = false,
}: PersonalSettingsViewProps) => {
const router = useRouter();
const { t } = useLocale();
const { data: user } = trpc.viewer.me.get.useQuery();
@@ -117,12 +122,14 @@ export const PersonalSettingsView = ({ userEmail, userName }: PersonalSettingsVi
subtitle={t("personal_details_subtitle")}
footer={
<div className="flex w-full items-center justify-end gap-4">
<Button
color="minimal"
className="rounded-[10px]"
onClick={() => router.push("/onboarding/getting-started")}>
{t("back")}
</Button>
{!fromTeamOnboarding && (
<Button
color="minimal"
className="rounded-[10px]"
onClick={() => router.push("/onboarding/getting-started")}>
{t("back")}
</Button>
)}
<Button
type="submit"
form="personal-settings-form"
@@ -113,16 +113,16 @@ export const TeamInviteEmailView = ({ userEmail }: TeamInviteEmailViewProps) =>
}
} else {
// No invites, skip to personal settings
const gettingStartedPath = "/onboarding/personal/settings";
router.push(gettingStartedPath);
const gettingStartedPath = "/onboarding/personal/settings?fromTeamOnboarding=true";
router.replace(gettingStartedPath);
}
};
const handleSkip = async () => {
setTeamInvites([]);
// Skip inviting members and go to personal settings
const gettingStartedPath = "/onboarding/personal/settings";
router.push(gettingStartedPath);
const gettingStartedPath = "/onboarding/personal/settings?fromTeamOnboarding=true";
router.replace(gettingStartedPath);
};
const hasValidInvites = fields.some((_, index) => {