Path: blob/main/components/dashboard/src/onboarding/StepUserInfo.tsx
2500 views
/**1* Copyright (c) 2023 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import { LinkedInProfile } from "@gitpod/gitpod-protocol";7import { FC, useCallback, useState } from "react";8import { TextInputField } from "../components/forms/TextInputField";9import { useUpdateCurrentUserMutation } from "../data/current-user/update-mutation";10import { useOnBlurError } from "../hooks/use-onblur-error";11import { OnboardingStep } from "./OnboardingStep";12import { LinkedInBanner } from "./LinkedInBanner";13import { User } from "@gitpod/public-api/lib/gitpod/v1/user_pb";14import { getPrimaryEmail } from "@gitpod/public-api-common/lib/user-utils";1516type Props = {17user: User;18onComplete(user: User): void;19};20export const StepUserInfo: FC<Props> = ({ user, onComplete }) => {21const updateUser = useUpdateCurrentUserMutation();22// attempt to split provided name for default input values23const { first, last } = getInitialNameParts(user);2425const [firstName, setFirstName] = useState(first);26const [lastName, setLastName] = useState(last);27// Email purposefully not pre-filled28const [emailAddress, setEmailAddress] = useState("");2930const handleSubmit = useCallback(async () => {31const updates = {32// we only split these out currently for form collection, but combine in the db33fullName: `${firstName} ${lastName}`,34additionalData: {35profile: {36// If still no email provided, default to "primary" email37emailAddress: emailAddress || getPrimaryEmail(user),38lastUpdatedDetailsNudge: new Date().toISOString(),39},40},41};4243try {44const updatedUser = await updateUser.mutateAsync(updates);45onComplete(updatedUser);46} catch (e) {47console.error(e);48}49}, [emailAddress, firstName, lastName, onComplete, updateUser, user]);5051const onLinkedInSuccess = useCallback(52async (profile: LinkedInProfile) => {53if (!firstName && profile.firstName) {54setFirstName(profile.firstName);55}56if (!lastName && profile.lastName) {57setLastName(profile.lastName);58}59if (!emailAddress && profile.emailAddress) {60setEmailAddress(profile.emailAddress);61}62handleSubmit();63},64[emailAddress, firstName, handleSubmit, lastName],65);6667const firstNameError = useOnBlurError("Please enter a value", !!firstName);68const lastNameError = useOnBlurError("Please enter a value", !!lastName);6970const isValid = [firstNameError, lastNameError].every((e) => e.isValid);7172return (73<OnboardingStep74title="Welcome to Gitpod"75subtitle="You are one step away from shipping software faster."76error={updateUser.isError ? "There was a problem updating your profile" : undefined}77isValid={isValid}78isSaving={updateUser.isLoading}79onSubmit={handleSubmit}80submitButtonText={"Continue with 10 hours per month"}81submitButtonType={"secondary"}82>83{user.avatarUrl && (84<div className="my-4 flex justify-center">85<img className="rounded-full w-24 h-24" src={user.avatarUrl} alt={user.name} />86</div>87)}8889<div className="flex justify-between space-x-2 w-full">90<TextInputField91containerClassName="w-1/2"92value={firstName}93label="First name"94error={firstNameError.message}95onBlur={firstNameError.onBlur}96onChange={setFirstName}97required98/>99100<TextInputField101containerClassName="w-1/2"102value={lastName}103label="Last name"104error={lastNameError.message}105onBlur={lastNameError.onBlur}106onChange={setLastName}107required108/>109</div>110111<LinkedInBanner onSuccess={onLinkedInSuccess} />112</OnboardingStep>113);114};115116// Intentionally not using User.getName() here to avoid relying on identity.authName (likely not user's real name)117const getInitialNameParts = (user: User) => {118const name = user.name || "";119let first = name;120let last = "";121122const parts = name.split(" ");123if (parts.length > 1) {124first = parts.shift() || "";125last = parts.join(" ");126}127128return { first, last };129};130131132