feat: add party user metadata storage and display support, including storage API, Redux actions, state management, and UI updates for profile page

This commit is contained in:
louiscklaw
2025-06-18 01:14:37 +08:00
parent c93b31b2f6
commit 215476cfaa
6 changed files with 55 additions and 14 deletions

View File

@@ -16,6 +16,8 @@ const USERNAME = 'username';
const ACCESS_TOKEN = 'a_token';
const ACTIVE_SESSION = 'a_session';
const PARTY_USER_META = 'party_user_meta';
export const getConfData = async () => {
console.log({ t: constants.API_ENDPOINT });
@@ -89,14 +91,21 @@ export const getUserData = async () => {
Storage.get({ key: HAS_LOGGED_IN }),
Storage.get({ key: HAS_SEEN_TUTORIAL }),
Storage.get({ key: USERNAME }),
Storage.get({ key: PARTY_USER_META }),
]);
const isLoggedin = (await response[0].value) === 'true';
const hasSeenTutorial = (await response[1].value) === 'true';
const username = (await response[2].value) || undefined;
let result = (await response[3].value) || undefined;
const meta = result ? JSON.parse(result) : undefined;
const data = {
isLoggedin,
hasSeenTutorial,
username,
meta,
};
return data;
};
@@ -120,6 +129,14 @@ export const setUsernameData = async (username?: string) => {
}
};
export const setPartyUserMetaData = async (party_user?: Record<string, any>) => {
if (!party_user) {
await Storage.remove({ key: PARTY_USER_META });
} else {
await Storage.set({ key: PARTY_USER_META, value: JSON.stringify(party_user) });
}
};
export const setAccessTokenData = async (accessToken?: string) => {
if (!accessToken) {
await Storage.remove({ key: ACCESS_TOKEN });

View File

@@ -6,6 +6,7 @@ import {
setAccessTokenData,
getAccessTokenData,
setActiveSessionData,
setPartyUserMetaData,
} from '../dataApi';
import { ActionType } from '../../util/types';
import { UserState } from './user.state';
@@ -34,6 +35,14 @@ export const setData = (data: Partial<UserState>) =>
data,
}) as const;
export const setPartyUserMeta = async (partyUserMeta: Record<string, any>) => {
await setPartyUserMetaData(partyUserMeta);
return {
type: 'set-party-user-meta',
partyUserMeta,
} as const;
};
export const logoutUser = () => async (dispatch: React.Dispatch<any>) => {
//
await setIsLoggedInData(false);
@@ -124,6 +133,7 @@ export const setDarkMode = (darkMode: boolean) =>
export type UserActions =
| ActionType<typeof setLoading>
| ActionType<typeof setData>
| ActionType<typeof setPartyUserMeta>
| ActionType<typeof setIsLoggedIn>
| ActionType<typeof setUsername>
| ActionType<typeof setHasSeenTutorial>

View File

@@ -19,6 +19,9 @@ export function userReducer(state: UserState, action: UserActions): UserState {
return { ...state, token: action.token };
case 'check-user-session':
return { ...state, isSessionValid: action.sessionValid };
case 'set-party-user-meta':
return { ...state, meta: action.partyUserMeta };
default:
return { ...state };
}

View File

@@ -9,14 +9,16 @@ export interface UserState {
token?: string;
//
name?: string;
email?: string;
avatarUrl?: string;
phoneNumber?: string;
company?: string;
role?: string;
rank?: string;
isVerified?: Boolean;
meta?: {
name?: string;
email?: string;
avatarUrl?: string;
phoneNumber?: string;
company?: string;
role?: string;
rank?: string;
isVerified?: Boolean;
};
//
accessToken?: string;

View File

@@ -151,7 +151,7 @@ const MyProfilePage: React.FC<PageProps> = ({
<IonAvatar>
<img
alt="Silhouette of a person's head"
src={partyUserState.avatarUrl ? partyUserState.avatarUrl : ''}
src={partyUserState?.meta?.avatarUrl ? partyUserState.meta.avatarUrl : ''}
/>
</IonAvatar>
<div style={{ flexGrow: 1 }}>
@@ -163,11 +163,11 @@ const MyProfilePage: React.FC<PageProps> = ({
}}
>
<div style={{ fontSize: '1.2rem', fontWeight: 'bold' }}>
{partyUserState.name}
{partyUserState.meta?.name}
</div>
<div style={{ fontSize: '0.8rem' }}>{partyUserState.rank}</div>
<div style={{ fontSize: '0.8rem' }}>{partyUserState.meta?.rank}</div>
<div style={{ fontSize: '0.8rem' }}>
{partyUserState.isVerified ? 'verified' : 'no'}
{partyUserState.meta?.isVerified ? 'verified' : 'no'}
</div>
</div>
</div>

View File

@@ -19,7 +19,12 @@ import {
IonToast,
} from '@ionic/react';
import './Login.scss';
import { setIsLoggedIn, setUsername, setData } from '../../data/user/user.actions';
import {
setIsLoggedIn,
setUsername,
setData,
setPartyUserMeta,
} from '../../data/user/user.actions';
import { connect } from '../../data/connect';
import { RouteComponentProps } from 'react-router';
import { chevronBackOutline } from 'ionicons/icons';
@@ -39,6 +44,7 @@ interface DispatchProps {
setIsLoggedIn: typeof setIsLoggedIn;
setUsername: typeof setUsername;
setData: typeof setData;
setPartyUserMeta: typeof setPartyUserMeta;
}
interface LoginProps extends OwnProps, DispatchProps {}
@@ -48,6 +54,7 @@ const Login: React.FC<LoginProps> = ({
history,
setUsername: setUsernameAction,
setData,
setPartyUserMeta,
}) => {
const [username, setUsername] = useState('demo@minimals.cc');
const [email, setEmail] = useState('demo@minimals.cc');
@@ -76,7 +83,8 @@ const Login: React.FC<LoginProps> = ({
if (status == 200) {
// if username and password ok
setData({ isLoggedin: true, accessToken, ...user });
setData({ isLoggedin: true, accessToken });
setPartyUserMeta(user);
await setIsLoggedIn(true);
await setUsernameAction(username);
@@ -192,6 +200,7 @@ export default connect<OwnProps, StateProps, DispatchProps>({
setIsLoggedIn,
setUsername,
setData,
setPartyUserMeta,
},
mapStateToProps: (state) => ({
partyUserState: selectors.getPartyUserState(state),