Skip to content

Commit

Permalink
feat(discussion): parse user name response (#10380)
Browse files Browse the repository at this point in the history
- remove unused UserNameResponse types and only keep relevant fields
- join all errors responses instead of only picking the first one
  • Loading branch information
mxdvl authored Jan 30, 2024
1 parent f50e88f commit 800435b
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 64 deletions.
5 changes: 2 additions & 3 deletions dotcom-rendering/src/components/Discussion/CommentForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -418,13 +418,12 @@ export const CommentForm = ({
}

const response = await addUserName(user.authStatus, userName);
if (response.status === 'ok') {
if (response.kind === 'ok') {
// If we are able to submit userName we should continue with submitting comment
void submitForm();
setUserNameMissing(false);
} else {
response.errors &&
setError(response.errors[0]?.message ?? 'unknown error');
setError(response.error);
}
};

Expand Down
26 changes: 22 additions & 4 deletions dotcom-rendering/src/lib/discussionApi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import type {
GetDiscussionSuccess,
OrderByType,
ThreadsType,
UserNameResponse,
} from '../types/discussion';
import {
discussionApiResponseSchema,
parseAbuseResponse,
parseCommentRepliesResponse,
parseCommentResponse,
postUsernameResponseSchema,
} from '../types/discussion';
import type { SignedInWithCookies, SignedInWithOkta } from './identity';
import { getOptionsHeadersWithOkta } from './identity';
Expand Down Expand Up @@ -337,11 +337,11 @@ export const recommend =
export const addUserName = async (
authStatus: SignedInWithCookies | SignedInWithOkta,
userName: string,
): Promise<UserNameResponse> => {
): Promise<Result<string, true>> => {
const url = options.idApiUrl + `/user/me/username`;
const authOptions = getOptionsHeadersWithOkta(authStatus);

const resp = await fetch(url, {
const jsonResult = await fetchJSON(url, {
method: 'POST',
body: JSON.stringify({
publicFields: {
Expand All @@ -356,7 +356,25 @@ export const addUserName = async (
credentials: authOptions.credentials,
});

return resp.json();
if (jsonResult.kind === 'error') {
return jsonResult;
}

const result = safeParse(postUsernameResponseSchema, jsonResult.value);

if (!result.success) {
return { kind: 'error', error: 'An unknown error occured' };
}
if (result.output.status === 'error') {
return {
kind: 'error',
error: result.output.errors
.map(({ message }) => message)
.join('\n'),
};
}

return { kind: 'ok', value: true };
};

export const pickComment = async (
Expand Down
72 changes: 15 additions & 57 deletions dotcom-rendering/src/types/discussion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
boolean,
integer,
literal,
minLength,
number,
object,
optional,
Expand Down Expand Up @@ -252,63 +253,20 @@ export const parseAbuseResponse = (data: unknown): Result<string, true> => {
: { kind: 'error', error: output.message };
};

type UserNameError = {
message: string;
description: string;
context: string;
};

type UserConsents = {
id: string;
actor: string;
version: number;
consented: boolean;
timestamp: string;
privacyPolicyVersion: number;
};

type UserGroups = {
path: string;
packageCode: string;
};

type UserNameUser = {
dates: { accountCreatedDate: string };
consents: UserConsents[];
userGroups: UserGroups[];
publicFields: {
username: string;
displayName: string;
};
statusFields: {
userEmailValidated: boolean;
};
privateFields: {
legacyPackages: string;
legacyProducts: string;
// Optional fields. See scala @ https://github.com/guardian/identity/blob/07142212b1571d5f8e0a60585c6511abb3620f8c/identity-model-play/src/main/scala/com/gu/identity/model/play/PrivateFields.scala#L5-L18
brazeUuid?: string;
puzzleUuid?: string;
googleTagId?: string;
firstName?: string;
secondName?: string;
registrationIp?: string;
lastActiveIpAddress?: string;
registrationType?: string;
registrationPlatform?: string;
telephoneNumber?: string;
title?: string;
};
primaryEmailAddress: string;
id: string;
hasPassword: boolean;
};

export type UserNameResponse = {
status: 'ok' | 'error';
user: UserNameUser;
errors?: UserNameError[];
};
export const postUsernameResponseSchema = variant('status', [
object({
status: literal('error'),
errors: array(
object({
message: string(),
}),
[minLength(1)],
),
}),
object({
status: literal('ok'),
}),
]);

const orderBy = ['newest', 'oldest', 'recommendations'] as const;
export const isOrderBy = guard(orderBy);
Expand Down

0 comments on commit 800435b

Please sign in to comment.