From f243236d00ad641357b92e5e22591f0fca9fdec5 Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Tue, 28 Nov 2023 11:17:46 -0300 Subject: [PATCH 01/17] change: create ProfileClass implementing Profile --- src/types/Profile.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/types/Profile.ts b/src/types/Profile.ts index 0acf5be5..9495c2ca 100644 --- a/src/types/Profile.ts +++ b/src/types/Profile.ts @@ -12,3 +12,16 @@ export type Profile = { bio: string | null; creationDate: string; } + +export class ProfileClass implements Profile { + constructor(private profile: Profile) {} + + get id() { return this.profile.id } + get user() { return this.profile.user } + get firstname() { return this.profile.firstname } + get lastname() { return this.profile.lastname } + get bio() { return this.profile.bio } + get gender() { return this.profile.gender } + get image() { return this.profile.image } + get creationDate() { return this.profile.creationDate } +} From 94b9b52528e818f88c499ce6c9513f88b2c35b73 Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Tue, 28 Nov 2023 11:23:11 -0300 Subject: [PATCH 02/17] change: ProfileClass setters --- src/types/Profile.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/types/Profile.ts b/src/types/Profile.ts index 9495c2ca..809ba09f 100644 --- a/src/types/Profile.ts +++ b/src/types/Profile.ts @@ -1,4 +1,5 @@ import type { User } from "@/types/User"; +import { type Nullable } from "@/types/utils"; export type Gender = "M" | "F" | "O"; @@ -17,11 +18,25 @@ export class ProfileClass implements Profile { constructor(private profile: Profile) {} get id() { return this.profile.id } + set id(id: string) { this.profile.id = id } + get user() { return this.profile.user } + set user(user: User) { this.profile.user = user } + get firstname() { return this.profile.firstname } + set firstname(firstname: Nullable) { this.profile.firstname = firstname } + get lastname() { return this.profile.lastname } + set lastname(lastname: Nullable) { this.profile.lastname = lastname } + get bio() { return this.profile.bio } + set bio(bio: Nullable) { this.profile.bio = bio } + get gender() { return this.profile.gender } + set gender(gender: Nullable) { this.profile.gender = gender } + get image() { return this.profile.image } + set image(image: Nullable) { this.profile.image = image } + get creationDate() { return this.profile.creationDate } } From 8ebf492e585f99a186d4e8d2d14fe49de335383f Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Tue, 28 Nov 2023 13:38:03 -0300 Subject: [PATCH 03/17] change: profileUtils functions as ProfileClass Methods --- src/types/Profile.ts | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/types/Profile.ts b/src/types/Profile.ts index 809ba09f..2b98113a 100644 --- a/src/types/Profile.ts +++ b/src/types/Profile.ts @@ -2,6 +2,11 @@ import type { User } from "@/types/User"; import { type Nullable } from "@/types/utils"; export type Gender = "M" | "F" | "O"; +export const GenderOptions: {[k in Gender]: string} = { + M: "Masculino", + F: "Feminino", + O: "Outro", +}; export type Profile = { id: string; @@ -17,6 +22,70 @@ export type Profile = { export class ProfileClass implements Profile { constructor(private profile: Profile) {} + /** + * Builds the full name of the profile. + * + * @returns {(string | null)} The concatenation of the first and last names, with a space in between + * or `null` if both are null. + */ + get fullname(): Nullable { + const hasFirst = this.firstname && this.firstname.length > 0; + const hasLast = this.lastname && this.lastname.length > 0; + + if (!hasFirst && !hasLast) + return null; + + return ( this.firstname ?? "" ) + + ( hasFirst && hasLast ? " " : "" ) + + ( this.lastname ?? "" ); + } + + /** + * User readable gender name, instead of the API value. + */ + get genderName() { + if (this.gender) + return GenderOptions[this.gender]; + + // todo: use a constant with this value + return "Não informado"; + } + + /** + * Image URL ready to be used on an ``. + */ + get imageUrl() { + if (this.image === null) + return null; + + return import.meta.env.VITE_UNIVERSIME_API + "/profile/image/" + this.id; + } + + /** + * Separates a full name into a first name and a last name. + * + * @param {string} fullname The full name to be separated. + * @returns {[string, string]} An 2 element array, where the first element is + * the first name and the second is the last name or `undefined`, if `fullname` + * doesn't have a last name. + */ + public static separateFullname(fullname: string): [string, string | undefined] { + fullname = fullname.trim(); + const spaceIndex = fullname.indexOf(" "); + + if (fullname.length === 0 || spaceIndex < 0) + return [fullname, undefined]; + + const firstname = fullname.slice(0, spaceIndex); + const lastname = fullname.slice(spaceIndex + 1); + + return [ + firstname, + lastname, + ]; + } + + /* Profile type getters and setters */ get id() { return this.profile.id } set id(id: string) { this.profile.id = id } From fd36cbec842bec36cdca6d9b51223f2c2fa2b468 Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Wed, 29 Nov 2023 09:43:51 -0300 Subject: [PATCH 04/17] change: imageUrl returns default when null --- src/types/Profile.ts | 3 ++- src/utils/assets.ts | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/types/Profile.ts b/src/types/Profile.ts index 2b98113a..ec8b5e7a 100644 --- a/src/types/Profile.ts +++ b/src/types/Profile.ts @@ -1,5 +1,6 @@ import type { User } from "@/types/User"; import { type Nullable } from "@/types/utils"; +import { IMG_DEFAULT_PROFILE } from "@/utils/assets"; export type Gender = "M" | "F" | "O"; export const GenderOptions: {[k in Gender]: string} = { @@ -56,7 +57,7 @@ export class ProfileClass implements Profile { */ get imageUrl() { if (this.image === null) - return null; + return IMG_DEFAULT_PROFILE; return import.meta.env.VITE_UNIVERSIME_API + "/profile/image/" + this.id; } diff --git a/src/utils/assets.ts b/src/utils/assets.ts index 05c11815..15d27b19 100644 --- a/src/utils/assets.ts +++ b/src/utils/assets.ts @@ -1,5 +1,6 @@ -export const IMG_UNIVERSI_LOGO = "/assets/imgs/universi-me2.png"; -export const IMG_DCX_LOGO = "/assets/imgs/dcx-png 1.png"; +export const IMG_UNIVERSI_LOGO = "/assets/imgs/universi-me2.png"; +export const IMG_DCX_LOGO = "/assets/imgs/dcx-png 1.png"; +export const IMG_DEFAULT_PROFILE = "/assets/imgs/default_avatar.png"; export const ICON_CHEVRON_DOWN = "/assets/icons/chevron-down-1.svg"; export const ICON_CHEVRON_UP_BLACK = "/assets/icons/chevron-up-black.svg"; From d2bb7a312c2cdc25418fd422389c06bd6d8cae2c Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Wed, 29 Nov 2023 09:53:19 -0300 Subject: [PATCH 05/17] change: creationDate as Date instead of string --- src/types/Profile.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/types/Profile.ts b/src/types/Profile.ts index ec8b5e7a..5103f3ed 100644 --- a/src/types/Profile.ts +++ b/src/types/Profile.ts @@ -62,6 +62,13 @@ export class ProfileClass implements Profile { return import.meta.env.VITE_UNIVERSIME_API + "/profile/image/" + this.id; } + /** + * Created date as `Date` instead of string; + */ + get createdAt() { + return new Date(this.creationDate); + } + /** * Separates a full name into a first name and a last name. * From cd22433c28e15aaa6ddfe3c046ab855769a3f46e Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 21:26:11 -0300 Subject: [PATCH 06/17] change: GENDER_OPTIONS instead of GenderOptions --- src/types/Profile.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/Profile.ts b/src/types/Profile.ts index 5103f3ed..9a55311e 100644 --- a/src/types/Profile.ts +++ b/src/types/Profile.ts @@ -3,7 +3,7 @@ import { type Nullable } from "@/types/utils"; import { IMG_DEFAULT_PROFILE } from "@/utils/assets"; export type Gender = "M" | "F" | "O"; -export const GenderOptions: {[k in Gender]: string} = { +export const GENDER_OPTIONS: {[k in Gender]: string} = { M: "Masculino", F: "Feminino", O: "Outro", @@ -46,7 +46,7 @@ export class ProfileClass implements Profile { */ get genderName() { if (this.gender) - return GenderOptions[this.gender]; + return GENDER_OPTIONS[this.gender]; // todo: use a constant with this value return "Não informado"; From 4b8479f8ede9e06baf18a7d6d033b40e1714d03e Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 21:29:12 -0300 Subject: [PATCH 07/17] change: use new GENDER_OPTIONS --- src/pages/ManageProfile/loader.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/ManageProfile/loader.ts b/src/pages/ManageProfile/loader.ts index 5a36ada4..a5179a8d 100644 --- a/src/pages/ManageProfile/loader.ts +++ b/src/pages/ManageProfile/loader.ts @@ -1,6 +1,5 @@ import UniversimeApi from "@/services/UniversimeApi"; -import { GENDER_OPTIONS } from "@/utils/profileUtils"; -import { Gender, Profile } from "@/types/Profile"; +import { type Gender, type Profile, GENDER_OPTIONS } from "@/types/Profile"; import { Link, TypeLink, TypeLinkToLabel } from "@/types/Link"; export type ManageProfileLoaderResponse = { From 9a12b5aa31f27af5473fa07cb4ddc9c287ef6f36 Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 21:51:11 -0300 Subject: [PATCH 08/17] change: use ProfileClass on RolesPage --- .../ProfileSettings/ProfileSettings.tsx | 3 +- src/pages/Settings/RolesPage/RolesPage.tsx | 40 ++++++++++--------- src/types/Profile.ts | 7 ++++ 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/pages/Profile/ProfileSettings/ProfileSettings.tsx b/src/pages/Profile/ProfileSettings/ProfileSettings.tsx index 76bbd3b5..e2423dd4 100644 --- a/src/pages/Profile/ProfileSettings/ProfileSettings.tsx +++ b/src/pages/Profile/ProfileSettings/ProfileSettings.tsx @@ -1,7 +1,8 @@ import { ChangeEvent, MouseEvent, useContext, useMemo, useState } from 'react'; import { ProfileContext } from '@/pages/Profile'; import { Link, TypeLink, TypeLinkToBootstrapIcon, TypeLinkToLabel } from '@/types/Link'; -import { getFullName, separateFullName, GENDER_OPTIONS } from '@/utils/profileUtils'; +import { getFullName, separateFullName } from '@/utils/profileUtils'; +import { GENDER_OPTIONS } from "@/types/Profile"; import { UniversimeApi } from '@/services/UniversimeApi'; import './ProfileSettings.css' diff --git a/src/pages/Settings/RolesPage/RolesPage.tsx b/src/pages/Settings/RolesPage/RolesPage.tsx index 3991ce8f..d6c7e47c 100644 --- a/src/pages/Settings/RolesPage/RolesPage.tsx +++ b/src/pages/Settings/RolesPage/RolesPage.tsx @@ -7,11 +7,10 @@ import { AuthContext } from "@/contexts/Auth"; import { SettingsTitle, type RolesPageLoaderResponse, RolesPageFetch, SettingsDescription } from "@/pages/Settings"; import { ProfileImage } from "@/components/ProfileImage/ProfileImage"; import { setStateAsValue } from "@/utils/tsxUtils"; -import { getFullName, getProfileImageUrl } from "@/utils/profileUtils"; import { type OptionInMenu, renderOption } from "@/utils/dropdownMenuUtils"; import * as SwalUtils from "@/utils/sweetalertUtils"; -import { type Profile } from "@/types/Profile"; +import { ProfileClass, type Profile } from "@/types/Profile"; import { UserAccessLevelLabel, type UserAccessLevel, compareAccessLevel } from "@/types/User"; import { type Optional } from "@/types/utils"; import "./RolesPage.less"; @@ -21,7 +20,7 @@ export function RolesPage() { const navigate = useNavigate(); const auth = useContext(AuthContext); - const [participants, participantsDispatch] = useReducer(participantsReducer, data.success ? data.participants : undefined); + const [participants, participantsDispatch] = useReducer(participantsReducer, data.success ? data.participants.map(ProfileClass.new) : undefined); const [filter, setFilter] = useState(""); if (!participants) { @@ -42,7 +41,7 @@ export function RolesPage() { return compareAccessLevel(a.user.accessLevel!, b.user.accessLevel!); } - return getFullName(a).localeCompare(getFullName(b)); + return (a.fullname ?? "").localeCompare(b.fullname ?? ""); }); const CHANGE_ROLE_OPTIONS: OptionInMenu[] = Object.entries(UserAccessLevelLabel).map(([role, label]) => ({ @@ -71,9 +70,9 @@ export function RolesPage() { const isOwnProfile = auth.profile!.id === profile.id; return
- +
-

{getFullName(profile)}

+

{profile.fullname}

{profile.bio}

@@ -105,18 +104,11 @@ export function RolesPage() { if (p.id !== action.profileId) return p; - const unchanging = data.participants + const originalRole = data.participants .find(p => p.id === action.profileId)! - .user.accessLevel === action.setRole; - - return { - ...p, - changed: unchanging ? undefined : true, - user: { - ...p.user, - accessLevel: action.setRole, - } - } + .user.accessLevel!; + + return new ProfileOnList(p, originalRole, action.setRole); }); } @@ -124,7 +116,7 @@ export function RolesPage() { const response = await RolesPageFetch(auth.organization!.id); participantsDispatch({ type: "SET_ALL", - setParticipants: response.success ? response.participants : undefined, + setParticipants: response.success ? response.participants.map(ProfileClass.new) : undefined, }); } @@ -154,7 +146,17 @@ export function RolesPage() { } } -type ProfileOnList = Profile & { changed?: true }; +class ProfileOnList extends ProfileClass { + public changed?: true; + + constructor(profile: Profile, originalRole: UserAccessLevel, newRole: UserAccessLevel) { + super(profile); + this.user.accessLevel = newRole; + this.changed = originalRole === newRole + ? true + : undefined; + } +} type ParticipantsReducerAction = { type: "SET_ROLE"; diff --git a/src/types/Profile.ts b/src/types/Profile.ts index 9a55311e..21dddedf 100644 --- a/src/types/Profile.ts +++ b/src/types/Profile.ts @@ -93,6 +93,13 @@ export class ProfileClass implements Profile { ]; } + /** + * The same as `new ProfileClass(profile)`, but can be used as a callback function. + */ + public static new(profile: Profile) { + return new ProfileClass(profile); + } + /* Profile type getters and setters */ get id() { return this.profile.id } set id(id: string) { this.profile.id = id } From 54794dc38f13c9da79e729b83139f2350b31ece7 Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 21:56:55 -0300 Subject: [PATCH 09/17] change: use ProfileClass on ProfilePage --- src/pages/Profile/ProfileContext.ts | 4 ++-- src/pages/Profile/ProfilePage.tsx | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/Profile/ProfileContext.ts b/src/pages/Profile/ProfileContext.ts index 4162d896..0bfafc92 100644 --- a/src/pages/Profile/ProfileContext.ts +++ b/src/pages/Profile/ProfileContext.ts @@ -1,5 +1,5 @@ import { createContext } from "react" -import type { Profile } from "@/types/Profile"; +import type { ProfileClass } from "@/types/Profile"; import type { Group } from "@/types/Group"; import type { Competence, CompetenceType, Level } from "@/types/Competence"; import type { Recommendation } from "@/types/Recommendation"; @@ -10,7 +10,7 @@ import type { Folder } from "@/types/Capacity"; export type ProfileContextType = null | { accessingLoggedUser: boolean; - profile: Profile; + profile: ProfileClass; editCompetence: Competence | null; allCompetenceTypes: CompetenceType[]; diff --git a/src/pages/Profile/ProfilePage.tsx b/src/pages/Profile/ProfilePage.tsx index 94d2549d..6d71684a 100644 --- a/src/pages/Profile/ProfilePage.tsx +++ b/src/pages/Profile/ProfilePage.tsx @@ -12,6 +12,7 @@ import * as SwalUtils from "@/utils/sweetalertUtils"; import { AuthContext } from "@/contexts/Auth"; import { SelectionBar } from "./SelectionBar/SelectionBar"; +import { ProfileClass } from "@/types/Profile"; import './Profile.css'; export function ProfilePage() { @@ -27,7 +28,7 @@ export function ProfilePage() { accessingLoggedUser: loaderData.accessingLoggedUser, allCompetenceTypes: loaderData.allCompetenceTypes, editCompetence: null, - profile: loaderData.profile!, + profile: new ProfileClass(loaderData.profile!), profileListData: { achievements: loaderData.profileListData.achievements, competences: loaderData.profileListData.competences, From 451b7b30ed130b18707ca3c7d75e05b26660c095 Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 22:07:32 -0300 Subject: [PATCH 10/17] change: ProfileClass on ProfileSettings --- src/pages/Profile/ProfileSettings/ProfileSettings.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/Profile/ProfileSettings/ProfileSettings.tsx b/src/pages/Profile/ProfileSettings/ProfileSettings.tsx index e2423dd4..94ff9f77 100644 --- a/src/pages/Profile/ProfileSettings/ProfileSettings.tsx +++ b/src/pages/Profile/ProfileSettings/ProfileSettings.tsx @@ -1,8 +1,7 @@ import { ChangeEvent, MouseEvent, useContext, useMemo, useState } from 'react'; import { ProfileContext } from '@/pages/Profile'; import { Link, TypeLink, TypeLinkToBootstrapIcon, TypeLinkToLabel } from '@/types/Link'; -import { getFullName, separateFullName } from '@/utils/profileUtils'; -import { GENDER_OPTIONS } from "@/types/Profile"; +import { GENDER_OPTIONS, ProfileClass } from "@/types/Profile"; import { UniversimeApi } from '@/services/UniversimeApi'; import './ProfileSettings.css' @@ -32,7 +31,7 @@ export function ProfileSettings(props: ProfileSettingsProps) {

Nome

- +
@@ -184,7 +183,7 @@ export function ProfileSettings(props: ProfileSettingsProps) { ? (genderElement as HTMLSelectElement).value : ''; - const [name, lastname] = separateFullName(fullname); + const [name, lastname] = ProfileClass.separateFullname(fullname); UniversimeApi.Profile.edit({ profileId: profileContext.profile.id, From 1cb7aef7bd9016fb95486641383bbd475ddc7ab6 Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 22:09:06 -0300 Subject: [PATCH 11/17] change: use ProfileClass on ProfileLastRecommendations --- .../ProfileLastRecommendations.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/pages/Profile/ProfileLastRecommendations/ProfileLastRecommendations.tsx b/src/pages/Profile/ProfileLastRecommendations/ProfileLastRecommendations.tsx index d4d8818e..b8fece31 100644 --- a/src/pages/Profile/ProfileLastRecommendations/ProfileLastRecommendations.tsx +++ b/src/pages/Profile/ProfileLastRecommendations/ProfileLastRecommendations.tsx @@ -1,9 +1,9 @@ import { useContext } from 'react'; import { Link } from 'react-router-dom'; import { ProfileContext } from '@/pages/Profile'; -import { getFullName, getProfileImageUrl } from '@/utils/profileUtils'; import { ProfileImage } from '@/components/ProfileImage/ProfileImage'; import './ProfileLastRecommendations.css' +import { ProfileClass } from '@/types/Profile'; const MAX_RECOMMENDATIONS_QUANTITY = 3; @@ -12,13 +12,15 @@ export function ProfileLastRecommendations() { if (profileContext === null) return null; + const recommendationsReceived = profileContext.profileListData.recommendationsReceived.map(r => ({ ...r, origin: new ProfileClass(r.origin), destiny: new ProfileClass(r.destiny) })); + return (

Últimas Recomendações

- { profileContext.profileListData.recommendationsReceived.length > 0 ? + { recommendationsReceived.length > 0 ?
{ - profileContext.profileListData.recommendationsReceived.map((recommendation, i) => { + recommendationsReceived.map((recommendation, i) => { if (i >= MAX_RECOMMENDATIONS_QUANTITY) return null; @@ -26,11 +28,11 @@ export function ProfileLastRecommendations() { return (
- +
- {getFullName(recommendation.origin)} + {recommendation.origin.fullname}

Recomendou pela competência:

{recommendation.competenceType.name}

From e6a96fe181a952de7a991c55b072fea4d9a4a6fd Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 22:11:20 -0300 Subject: [PATCH 12/17] change: use ProfileClass on ProfileBio --- src/components/ProfileInfo/ProfileBio/ProfileBio.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/ProfileInfo/ProfileBio/ProfileBio.tsx b/src/components/ProfileInfo/ProfileBio/ProfileBio.tsx index 7607ea51..28ff716d 100644 --- a/src/components/ProfileInfo/ProfileBio/ProfileBio.tsx +++ b/src/components/ProfileInfo/ProfileBio/ProfileBio.tsx @@ -1,11 +1,10 @@ import { Link } from 'react-router-dom'; import { ProfileImage } from '@/components/ProfileImage/ProfileImage'; -import { getFullName, getProfileImageUrl } from '@/utils/profileUtils'; import { ICON_EDIT_WHITE } from '@/utils/assets'; import { groupBannerUrl } from '@/utils/apiUtils'; -import type { Profile } from '@/types/Profile'; +import { type Profile, ProfileClass } from '@/types/Profile'; import { TypeLinkToBootstrapIcon, type Link as Link_API } from '@/types/Link'; import type { Group } from '@/types/Group'; import './ProfileBio.less'; @@ -26,6 +25,8 @@ export function ProfileBio(props: ProfileBioProps) { ? { backgroundImage: `url(${groupBannerUrl(props.organization)})` } : { backgroundColor: "var(--primary-color)" } + const profile = new ProfileClass(props.profile); + return (
@@ -42,11 +43,11 @@ export function ProfileBio(props: ProfileBioProps) {
- + { isOnOwnProfile - ?

{ getFullName(props.profile) }

- : { getFullName(props.profile) } + ?

{ profile.fullname }

+ : { profile.fullname } } { props.profile.bio === null || props.profile.bio.length === 0 From 949a8ab3a601d2b41be676e43d36afddcade8ccd Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 22:13:37 -0300 Subject: [PATCH 13/17] change: use ProfileClass on GroupContext --- src/pages/Group/Group.tsx | 5 +++-- src/pages/Group/GroupContext.tsx | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pages/Group/Group.tsx b/src/pages/Group/Group.tsx index f1fdff8d..9075aeb6 100644 --- a/src/pages/Group/Group.tsx +++ b/src/pages/Group/Group.tsx @@ -5,6 +5,7 @@ import { GroupContext, GroupIntro, GroupTabRenderer, GroupTabs, fetchGroupPageDa import { ProfileInfo } from "@/components/ProfileInfo/ProfileInfo"; import { AuthContext } from "@/contexts/Auth"; import "./Group.less"; +import { ProfileClass } from "@/types/Profile"; export function GroupPage() { const page = useLoaderData() as GroupPageLoaderResponse; @@ -72,11 +73,11 @@ export function GroupPage() { group: data.group!, loggedData: { isParticipant: data.loggedData?.isParticipant!, - profile: data.loggedData?.profile!, + profile: new ProfileClass(data.loggedData?.profile!), links: data.loggedData?.links ?? [], groups: data.loggedData?.groups ?? [], }, - participants: data.participants, + participants: data.participants.map(ProfileClass.new), subgroups: data.subGroups, currentContent: undefined, diff --git a/src/pages/Group/GroupContext.tsx b/src/pages/Group/GroupContext.tsx index 61fbe989..0d5730b8 100644 --- a/src/pages/Group/GroupContext.tsx +++ b/src/pages/Group/GroupContext.tsx @@ -1,13 +1,13 @@ import { createContext } from "react"; import { Group } from "@/types/Group"; -import { Profile } from "@/types/Profile"; +import { type ProfileClass } from "@/types/Profile"; import type { Content, Folder } from "@/types/Capacity"; import { Link } from "@/types/Link"; export type GroupContextType = null | { group: Group; subgroups: Group[]; - participants: Profile[]; + participants: ProfileClass[]; folders: Folder[]; currentContent: Folder | undefined; @@ -33,7 +33,7 @@ export type GroupContextType = null | { loggedData: { isParticipant: boolean; - profile: Profile; + profile: ProfileClass; links: Link[]; groups: Group[]; }; From 0190028377f64808ac6561a7154da18f8869724c Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 22:15:10 -0300 Subject: [PATCH 14/17] change: use ProfileClass on GroupPeople --- src/pages/Group/GroupTabs/GroupPeople/GroupPeople.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pages/Group/GroupTabs/GroupPeople/GroupPeople.tsx b/src/pages/Group/GroupTabs/GroupPeople/GroupPeople.tsx index c69aac12..b68ad1e9 100644 --- a/src/pages/Group/GroupTabs/GroupPeople/GroupPeople.tsx +++ b/src/pages/Group/GroupTabs/GroupPeople/GroupPeople.tsx @@ -3,9 +3,8 @@ import { Link } from "react-router-dom"; import { EMPTY_LIST_CLASS, GroupContext } from "@/pages/Group"; import { setStateAsValue } from "@/utils/tsxUtils"; -import { Profile } from "@/types/Profile"; +import { ProfileClass } from "@/types/Profile"; import { ProfileImage } from "@/components/ProfileImage/ProfileImage"; -import { getFullName } from "@/utils/profileUtils"; import "./GroupPeople.less"; import { Filter } from "@/components/Filter/Filter"; @@ -33,7 +32,7 @@ export function GroupPeople() { ); } -function makePeopleList(people: Profile[], filter: string) { +function makePeopleList(people: ProfileClass[], filter: string) { if (people.length === 0) { return

Esse grupo não possui participantes.

} @@ -41,7 +40,7 @@ function makePeopleList(people: Profile[], filter: string) { const lowercaseFilter = filter.toLowerCase(); const filteredPeople = filter.length === 0 ? people - : people.filter(p => (getFullName(p)).toLowerCase().includes(lowercaseFilter)); + : people.filter(p => (p.fullname ?? "").toLowerCase().includes(lowercaseFilter)); if (filteredPeople.length === 0) { return

Nenhum participante encontrado com a pesquisa.

@@ -52,7 +51,7 @@ function makePeopleList(people: Profile[], filter: string) { .map(renderPerson); } -function renderPerson(person: Profile) { +function renderPerson(person: ProfileClass) { const linkToProfile = `/profile/${person.user.name}`; const imageUrl = person.image?.startsWith("/") @@ -66,7 +65,7 @@ function renderPerson(person: Profile) {
- {getFullName(person)} + {person.fullname}

{person.bio}

From 0c60c4cc25bbb4a4ec2e6242beeca02b7107681e Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 22:20:09 -0300 Subject: [PATCH 15/17] change: use ProfileClass on ManageProfile --- src/pages/ManageProfile/ManageProfile.tsx | 3 +-- src/pages/ManageProfile/loader.ts | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pages/ManageProfile/ManageProfile.tsx b/src/pages/ManageProfile/ManageProfile.tsx index b059d938..b645f765 100644 --- a/src/pages/ManageProfile/ManageProfile.tsx +++ b/src/pages/ManageProfile/ManageProfile.tsx @@ -4,7 +4,6 @@ import { Navigate, useLoaderData, useNavigate } from "react-router-dom"; import UniversimeApi from "@/services/UniversimeApi"; import { ManageProfileLinks, ManageProfileLoaderResponse, ManageProfilePassword, ManageProfileImage, getManageLinks, getProfileImage } from "@/pages/ManageProfile"; import { setStateAsValue } from "@/utils/tsxUtils"; -import { getProfileImageUrl } from "@/utils/profileUtils"; import { AuthContext } from "@/contexts/Auth"; import * as SwalUtils from "@/utils/sweetalertUtils"; @@ -38,7 +37,7 @@ export function ManageProfilePage() {
- +
Altere seu nome diff --git a/src/pages/ManageProfile/loader.ts b/src/pages/ManageProfile/loader.ts index a5179a8d..25374cde 100644 --- a/src/pages/ManageProfile/loader.ts +++ b/src/pages/ManageProfile/loader.ts @@ -1,9 +1,9 @@ import UniversimeApi from "@/services/UniversimeApi"; -import { type Gender, type Profile, GENDER_OPTIONS } from "@/types/Profile"; +import { type Gender, ProfileClass, GENDER_OPTIONS } from "@/types/Profile"; import { Link, TypeLink, TypeLinkToLabel } from "@/types/Link"; export type ManageProfileLoaderResponse = { - profile: Profile | null; + profile: ProfileClass | null; links: Link[]; genderOptions: { @@ -45,7 +45,7 @@ export async function ManageProfileLoader(): Promise Date: Fri, 1 Dec 2023 22:20:45 -0300 Subject: [PATCH 16/17] change: use ProfileClass on AuthContext --- .../components/WelcomeUser/WelcomeUser.tsx | 3 +-- src/contexts/Auth/AuthContext.tsx | 10 +++++----- src/contexts/Auth/AuthProvider.tsx | 10 +++++++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/components/UniversiHeader/components/WelcomeUser/WelcomeUser.tsx b/src/components/UniversiHeader/components/WelcomeUser/WelcomeUser.tsx index 49f7c145..93dc7485 100644 --- a/src/components/UniversiHeader/components/WelcomeUser/WelcomeUser.tsx +++ b/src/components/UniversiHeader/components/WelcomeUser/WelcomeUser.tsx @@ -3,7 +3,6 @@ import { Link, redirect, useNavigate } from "react-router-dom"; import { ProfileImage } from "@/components/ProfileImage/ProfileImage"; import { AuthContext } from "@/contexts/Auth"; import "./WelcomeUser.less" -import { getProfileImageUrl } from "@/utils/profileUtils"; import * as DropdownMenu from "@radix-ui/react-dropdown-menu" export function WelcomeUser() { @@ -20,7 +19,7 @@ export function WelcomeUser() { return( !isLogged ? null :
- {setProfileClicked(!profileClicked)}}/> + {setProfileClicked(!profileClicked)}}/> { profileClicked ? diff --git a/src/contexts/Auth/AuthContext.tsx b/src/contexts/Auth/AuthContext.tsx index 3089fcbf..762db9fa 100644 --- a/src/contexts/Auth/AuthContext.tsx +++ b/src/contexts/Auth/AuthContext.tsx @@ -1,18 +1,18 @@ import { createContext } from "react"; import { User } from "@/types/User"; -import { Profile } from "@/types/Profile"; +import { type ProfileClass } from "@/types/Profile"; import type { Group } from "@/types/Group"; export type AuthContextType = { user : User | null; - profile: Profile | null; + profile: ProfileClass | null; organization: Group | null; - signin: (email : string, password: string, recaptchaToken: string | null) => Promise; - signinGoogle: () => Promise; + signin: (email : string, password: string, recaptchaToken: string | null) => Promise; + signinGoogle: () => Promise; signout: () => Promise; - updateLoggedUser: () => Promise; + updateLoggedUser: () => Promise; } export const AuthContext = createContext(null!); diff --git a/src/contexts/Auth/AuthProvider.tsx b/src/contexts/Auth/AuthProvider.tsx index f2442bf4..926f7b0c 100644 --- a/src/contexts/Auth/AuthProvider.tsx +++ b/src/contexts/Auth/AuthProvider.tsx @@ -1,12 +1,12 @@ import { ReactNode, useEffect, useState } from "react"; import { AuthContext } from "./AuthContext"; -import { Profile } from "@/types/Profile"; +import { ProfileClass } from "@/types/Profile"; import { UniversimeApi } from "@/services/UniversimeApi"; import { goTo } from "@/services/routes"; import type { Group } from "@/types/Group"; export const AuthProvider = ({ children }: { children: ReactNode }) => { - const [profile, setProfile] = useState(null); + const [profile, setProfile] = useState(null); const [organization, setOrganization] = useState(null); const [finishedLogin, setFinishedLogin] = useState(false); const user = profile?.user ?? null; @@ -90,5 +90,9 @@ async function getLoggedProfile() { if(!await UniversimeApi.Auth.validateToken()) { return null; } - return (await UniversimeApi.Profile.profile()).body?.profile ?? null; + + const responseProfile = (await UniversimeApi.Profile.profile()).body?.profile; + return responseProfile + ? new ProfileClass(responseProfile) + : null; } From 4aebbf991ea0d3a2aae432d178e27f299917f917 Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Fri, 1 Dec 2023 22:22:03 -0300 Subject: [PATCH 17/17] change: delete profileUtils.ts --- src/utils/profileUtils.ts | 40 --------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 src/utils/profileUtils.ts diff --git a/src/utils/profileUtils.ts b/src/utils/profileUtils.ts deleted file mode 100644 index 6c792698..00000000 --- a/src/utils/profileUtils.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { Profile, Gender } from "@/types/Profile" - -export const GENDER_OPTIONS = { - "M": "Masculino", - "F": "Feminino", - "O": "Outro", -} - -export function getFullName(profile: Profile): string { - const first = profile.firstname ?? ""; - const last = profile.lastname ?? ""; - - return `${first}${first != "" ? " " : ""}${last}` -} - -export function separateFullName(fullname: string): [string, string] { - const names = fullname.split(' '); - - if (names.length <= 0) - return ['', '']; - - return [ - names[0], - names.slice(1).join(' ') - ] -} - -export function getGenderName(gender: Gender | null | undefined): string { - return gender ? GENDER_OPTIONS[gender] : 'Não informado'; -} - -export function getProfileImageUrl(profile: Profile): string | null { - if (!profile.image) { - return "/assets/imgs/default_avatar.png"; - } - - return profile.image.startsWith("/") - ? `${import.meta.env.VITE_UNIVERSIME_API}${profile.image}` - : profile.image; -}