Skip to content

Commit e44ab89

Browse files
committed
use useUpdateCurrentUserMutation and make it fetch current state first
1 parent 6e11f4b commit e44ab89

File tree

10 files changed

+82
-59
lines changed

10 files changed

+82
-59
lines changed

components/dashboard/src/AppNotifications.tsx

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import dayjs from "dayjs";
88
import { useCallback, useEffect, useState } from "react";
99
import Alert, { AlertType } from "./components/Alert";
1010
import { useUserLoader } from "./hooks/use-user-loader";
11-
import { getGitpodService } from "./service/service";
1211
import { isGitpodIo } from "./utils";
1312
import { trackEvent } from "./Analytics";
13+
import { useUpdateCurrentUserMutation } from "./data/current-user/update-mutation";
14+
import { User as UserProtocol } from "@gitpod/gitpod-protocol";
15+
import { User } from "@gitpod/public-api/lib/gitpod/v1/user_pb";
1416

1517
const KEY_APP_DISMISSED_NOTIFICATIONS = "gitpod-app-notifications-dismissed";
1618
const PRIVACY_POLICY_LAST_UPDATED = "2023-10-17";
@@ -23,41 +25,44 @@ interface Notification {
2325
onClose?: () => void;
2426
}
2527

26-
const UPDATED_PRIVACY_POLICY: Notification = {
27-
id: "privacy-policy-update",
28-
type: "info",
29-
preventDismiss: true,
30-
onClose: async () => {
31-
let dismissSuccess = false;
32-
try {
33-
const updatedUser = await getGitpodService().server.updateLoggedInUser({
34-
additionalData: { profile: { acceptedPrivacyPolicyDate: dayjs().toISOString() } },
35-
});
36-
dismissSuccess = !!updatedUser;
37-
} catch (err) {
38-
console.error("Failed to update user's privacy policy acceptance date", err);
39-
dismissSuccess = false;
40-
} finally {
41-
trackEvent("privacy_policy_update_accepted", {
42-
path: window.location.pathname,
43-
success: dismissSuccess,
44-
});
45-
}
46-
},
47-
message: (
48-
<span className="text-md">
49-
We've updated our Privacy Policy. You can review it{" "}
50-
<a className="gp-link" href="https://www.gitpod.io/privacy" target="_blank" rel="noreferrer">
51-
here
52-
</a>
53-
.
54-
</span>
55-
),
28+
const UPDATED_PRIVACY_POLICY = (updateUser: (user: Partial<UserProtocol>) => Promise<User>) => {
29+
return {
30+
id: "privacy-policy-update",
31+
type: "info",
32+
preventDismiss: true,
33+
onClose: async () => {
34+
let dismissSuccess = false;
35+
try {
36+
const updatedUser = await updateUser({
37+
additionalData: { profile: { acceptedPrivacyPolicyDate: dayjs().toISOString() } },
38+
});
39+
dismissSuccess = !!updatedUser;
40+
} catch (err) {
41+
console.error("Failed to update user's privacy policy acceptance date", err);
42+
dismissSuccess = false;
43+
} finally {
44+
trackEvent("privacy_policy_update_accepted", {
45+
path: window.location.pathname,
46+
success: dismissSuccess,
47+
});
48+
}
49+
},
50+
message: (
51+
<span className="text-md">
52+
We've updated our Privacy Policy. You can review it{" "}
53+
<a className="gp-link" href="https://www.gitpod.io/privacy" target="_blank" rel="noreferrer">
54+
here
55+
</a>
56+
.
57+
</span>
58+
),
59+
} as Notification;
5660
};
5761

5862
export function AppNotifications() {
5963
const [topNotification, setTopNotification] = useState<Notification | undefined>(undefined);
6064
const { user, loading } = useUserLoader();
65+
const updateUser = useUpdateCurrentUserMutation();
6166

6267
useEffect(() => {
6368
const notifications = [];
@@ -66,14 +71,14 @@ export function AppNotifications() {
6671
!user?.profile?.acceptedPrivacyPolicyDate ||
6772
new Date(PRIVACY_POLICY_LAST_UPDATED) > new Date(user.profile.acceptedPrivacyPolicyDate)
6873
) {
69-
notifications.push(UPDATED_PRIVACY_POLICY);
74+
notifications.push(UPDATED_PRIVACY_POLICY((u: Partial<UserProtocol>) => updateUser.mutateAsync(u)));
7075
}
7176
}
7277

7378
const dismissedNotifications = getDismissedNotifications();
7479
const topNotification = notifications.find((n) => !dismissedNotifications.includes(n.id));
7580
setTopNotification(topNotification);
76-
}, [loading, setTopNotification, user]);
81+
}, [loading, updateUser, setTopNotification, user]);
7782

7883
const dismissNotification = useCallback(() => {
7984
if (!topNotification) {

components/dashboard/src/components/AuthorizeGit.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ export const AuthorizeGit: FC<{ className?: string }> = ({ className }) => {
2929
const { refetch: reloadUser } = useAuthenticatedUser();
3030
const owner = useIsOwner();
3131
const { data: authProviders } = useAuthProviderDescriptions();
32-
const updateUser = useCallback(() => {
33-
reloadUser();
32+
const updateUser = useCallback(async () => {
33+
await reloadUser();
3434
}, [reloadUser]);
3535

3636
const connect = useCallback(

components/dashboard/src/data/current-user/update-mutation.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,28 @@
44
* See License.AGPL.txt in the project root for license information.
55
*/
66

7-
import { User } from "@gitpod/gitpod-protocol";
7+
import { User as UserProtocol } from "@gitpod/gitpod-protocol";
88
import { useMutation } from "@tanstack/react-query";
99
import { trackEvent } from "../../Analytics";
1010
import { getGitpodService } from "../../service/service";
1111
import { useAuthenticatedUser } from "./authenticated-user-query";
1212
import { converter } from "../../service/public-api";
1313

14-
type UpdateCurrentUserArgs = Partial<User>;
14+
type UpdateCurrentUserArgs = Partial<UserProtocol>;
1515

1616
export const useUpdateCurrentUserMutation = () => {
1717
return useMutation({
1818
mutationFn: async (partialUser: UpdateCurrentUserArgs) => {
19-
const user = await getGitpodService().server.updateLoggedInUser(partialUser);
19+
const current = await getGitpodService().server.getLoggedInUser();
20+
const update: UpdateCurrentUserArgs = {
21+
id: current.id,
22+
fullName: partialUser.fullName || current.fullName,
23+
additionalData: {
24+
...current.additionalData,
25+
...partialUser.additionalData,
26+
},
27+
};
28+
const user = await getGitpodService().server.updateLoggedInUser(update);
2029
return converter.toUser(user);
2130
},
2231
});

components/dashboard/src/dedicated-setup/DedicatedSetup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ const DedicatedSetupSteps: FC<DedicatedSetupStepsProps> = ({ org, ssoConfig, onC
9797

9898
const updateUser = useCallback(async () => {
9999
await getGitpodService().reconnect();
100-
reloadUser();
100+
await reloadUser();
101101
}, [reloadUser]);
102102

103103
const handleEndSetup = useCallback(async () => {

components/dashboard/src/onboarding/UserOnboarding.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ const UserOnboarding: FunctionComponent<Props> = ({ user }) => {
8282
});
8383

8484
dropConfetti();
85-
reloadUser();
85+
await reloadUser();
8686

8787
// Look for the `onboarding=force` query param, and remove if present
8888
const queryParams = new URLSearchParams(location.search);

components/dashboard/src/user-settings/Account.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { useAuthenticatedUser } from "../data/current-user/authenticated-user-qu
2020
import { getPrimaryEmail, getProfile, isOrganizationOwned } from "@gitpod/gitpod-protocol/lib/public-api-utils";
2121
import { User } from "@gitpod/public-api/lib/gitpod/v1/user_pb";
2222
import { User as UserProtocol } from "@gitpod/gitpod-protocol";
23+
import { useUpdateCurrentUserMutation } from "../data/current-user/update-mutation";
2324

2425
export default function Account() {
2526
const { data: user, refetch: reloadUser } = useAuthenticatedUser();
@@ -30,6 +31,7 @@ export default function Account() {
3031
const [errorMessage, setErrorMessage] = useState("");
3132
const canUpdateEmail = user && !isOrganizationOwned(user);
3233
const { toast } = useToast();
34+
const updateUser = useUpdateCurrentUserMutation();
3335

3436
const saveProfileState = useCallback(async () => {
3537
if (!user || !profileState) {
@@ -54,14 +56,14 @@ export default function Account() {
5456
profileState.email = getPrimaryEmail(user) || "";
5557
}
5658

57-
await getGitpodService().server.updateLoggedInUser({
59+
await updateUser.mutateAsync({
5860
additionalData: {
5961
profile: profileState,
6062
},
6163
});
6264
reloadUser();
6365
toast("Your profile information has been updated.");
64-
}, [canUpdateEmail, profileState, reloadUser, toast, user]);
66+
}, [updateUser, canUpdateEmail, profileState, reloadUser, toast, user]);
6567

6668
const deleteAccount = useCallback(async () => {
6769
await getGitpodService().server.deleteAccount();

components/dashboard/src/user-settings/Notifications.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,32 @@
55
*/
66

77
import { useState } from "react";
8-
import { getGitpodService } from "../service/service";
98
import { CheckboxInputField } from "../components/forms/CheckboxInputField";
109
import { identifyUser } from "../Analytics";
1110
import { PageWithSettingsSubMenu } from "./PageWithSettingsSubMenu";
1211
import { Heading2 } from "../components/typography/headings";
1312
import { useAuthenticatedUser } from "../data/current-user/authenticated-user-query";
13+
import { useUpdateCurrentUserMutation } from "../data/current-user/update-mutation";
1414

1515
export default function Notifications() {
1616
const { data: user, refetch: reloadUser } = useAuthenticatedUser();
1717
const [isOnboardingMail, setOnboardingMail] = useState(!!user?.emailNotificationSettings?.allowsOnboardingMail);
1818
const [isChangelogMail, setChangelogMail] = useState(!!user?.emailNotificationSettings?.allowsChangelogMail);
1919
const [isDevXMail, setDevXMail] = useState(!!user?.emailNotificationSettings?.allowsDevxMail);
20+
const updateUser = useUpdateCurrentUserMutation();
2021

2122
const toggleOnboardingMail = async () => {
2223
if (user && user.emailNotificationSettings) {
2324
const newIsOnboardingMail = !isOnboardingMail;
2425
user.emailNotificationSettings.allowsOnboardingMail = newIsOnboardingMail;
25-
await getGitpodService().server.updateLoggedInUser({
26+
await updateUser.mutateAsync({
2627
additionalData: {
2728
emailNotificationSettings: {
2829
allowsOnboardingMail: newIsOnboardingMail,
2930
},
3031
},
3132
});
32-
reloadUser();
33+
await reloadUser();
3334
identifyUser({ unsubscribed_onboarding: !newIsOnboardingMail });
3435
setOnboardingMail(newIsOnboardingMail);
3536
}
@@ -39,14 +40,14 @@ export default function Notifications() {
3940
if (user && user.emailNotificationSettings) {
4041
const newIsChangelogMail = !isChangelogMail;
4142
user.emailNotificationSettings.allowsChangelogMail = newIsChangelogMail;
42-
await getGitpodService().server.updateLoggedInUser({
43+
await updateUser.mutateAsync({
4344
additionalData: {
4445
emailNotificationSettings: {
4546
allowsChangelogMail: newIsChangelogMail,
4647
},
4748
},
4849
});
49-
reloadUser();
50+
await reloadUser();
5051
identifyUser({ unsubscribed_changelog: !newIsChangelogMail });
5152
setChangelogMail(newIsChangelogMail);
5253
}
@@ -56,7 +57,7 @@ export default function Notifications() {
5657
if (user && user.emailNotificationSettings) {
5758
const newIsDevXMail = !isDevXMail;
5859
user.emailNotificationSettings.allowsDevxMail = newIsDevXMail;
59-
await getGitpodService().server.updateLoggedInUser({
60+
await updateUser.mutateAsync({
6061
additionalData: {
6162
emailNotificationSettings: {
6263
allowsDevXMail: newIsDevXMail,

components/dashboard/src/user-settings/Preferences.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ import SelectIDE from "./SelectIDE";
1515
import { InputField } from "../components/forms/InputField";
1616
import { TextInput } from "../components/forms/TextInputField";
1717
import { useToast } from "../components/toasts/Toasts";
18-
import { useUpdateCurrentUserDotfileRepoMutation } from "../data/current-user/update-mutation";
18+
import {
19+
useUpdateCurrentUserDotfileRepoMutation,
20+
useUpdateCurrentUserMutation,
21+
} from "../data/current-user/update-mutation";
1922
import { useOrgBillingMode } from "../data/billing-mode/org-billing-mode-query";
2023
import { useAuthenticatedUser } from "../data/current-user/authenticated-user-query";
2124
import { converter } from "../service/public-api";
@@ -25,6 +28,7 @@ export type IDEChangedTrackLocation = "workspace_list" | "workspace_start" | "pr
2528
export default function Preferences() {
2629
const { toast } = useToast();
2730
const { data: user, refetch: reloadUser } = useAuthenticatedUser();
31+
const updateUser = useUpdateCurrentUserMutation();
2832
const billingMode = useOrgBillingMode();
2933
const updateDotfileRepo = useUpdateCurrentUserDotfileRepoMutation();
3034

@@ -41,7 +45,7 @@ export default function Preferences() {
4145
e.preventDefault();
4246

4347
await updateDotfileRepo.mutateAsync(dotfileRepo);
44-
reloadUser();
48+
await reloadUser();
4549
toast("Your dotfiles repository was updated.");
4650
},
4751
[updateDotfileRepo, dotfileRepo, reloadUser, toast],
@@ -57,7 +61,7 @@ export default function Preferences() {
5761
await getGitpodService().server.updateWorkspaceTimeoutSetting({ workspaceTimeout: workspaceTimeout });
5862

5963
// TODO: Once current user is in react-query, we can instead invalidate the query vs. refetching here
60-
reloadUser();
64+
await reloadUser();
6165

6266
let toastMessage = <>Default workspace timeout was updated.</>;
6367
if (billingMode.data?.mode === "usage-based") {
@@ -89,14 +93,14 @@ export default function Preferences() {
8993
if (!user) {
9094
return;
9195
}
92-
await getGitpodService().server.updateLoggedInUser({
96+
await updateUser.mutateAsync({
9397
additionalData: {
9498
workspaceAutostartOptions: [],
9599
},
96100
});
97-
reloadUser();
101+
await reloadUser();
98102
toast("Workspace options have been cleared.");
99-
}, [reloadUser, toast, user]);
103+
}, [updateUser, reloadUser, toast, user]);
100104

101105
return (
102106
<div>

components/dashboard/src/user-settings/SelectIDE.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export default function SelectIDE(props: SelectIDEProps) {
3535
},
3636
};
3737
await updateUser.mutateAsync(updates);
38-
reloadUser();
38+
await reloadUser();
3939
},
4040
[reloadUser, updateUser],
4141
);

components/dashboard/src/workspaces/CreateWorkspacePage.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { useListWorkspacesQuery } from "../data/workspaces/list-workspaces-query
2828
import { useWorkspaceContext } from "../data/workspaces/resolve-context-query";
2929
import { useDirtyState } from "../hooks/use-dirty-state";
3030
import { openAuthorizeWindow } from "../provider-utils";
31-
import { getGitpodService, gitpodHostUrl } from "../service/service";
31+
import { gitpodHostUrl } from "../service/service";
3232
import { StartWorkspaceError } from "../start/StartPage";
3333
import { VerifyModal } from "../start/VerifyModal";
3434
import { StartWorkspaceOptions } from "../start/start-workspace-options";
@@ -45,9 +45,11 @@ import { useAuthenticatedUser } from "../data/current-user/authenticated-user-qu
4545
import { User_WorkspaceAutostartOption } from "@gitpod/public-api/lib/gitpod/v1/user_pb";
4646
import { EditorReference } from "@gitpod/public-api/lib/gitpod/v1/editor_pb";
4747
import { converter } from "../service/public-api";
48+
import { useUpdateCurrentUserMutation } from "../data/current-user/update-mutation";
4849

4950
export function CreateWorkspacePage() {
5051
const { data: user, refetch: reloadUser } = useAuthenticatedUser();
52+
const updateUser = useUpdateCurrentUserMutation();
5153
const currentOrg = useCurrentOrg().data;
5254
const projects = useListAllProjectsQuery();
5355
const workspaces = useListWorkspacesQuery({ limit: 50 });
@@ -106,15 +108,15 @@ export function CreateWorkspacePage() {
106108
}),
107109
}),
108110
);
109-
await getGitpodService().server.updateLoggedInUser({
111+
await updateUser.mutateAsync({
110112
additionalData: {
111113
workspaceAutostartOptions: workspaceAutoStartOptions.map((o) =>
112114
converter.fromWorkspaceAutostartOption(o),
113115
),
114116
},
115117
});
116-
reloadUser();
117-
}, [currentOrg, selectedIde, selectedWsClass, reloadUser, useLatestIde, user, workspaceContext.data]);
118+
await reloadUser();
119+
}, [updateUser, currentOrg, selectedIde, selectedWsClass, reloadUser, useLatestIde, user, workspaceContext.data]);
118120

119121
// see if we have a matching project based on context url and project's repo url
120122
const project = useMemo(() => {

0 commit comments

Comments
 (0)