Files
HKSingleParty/03_source/mobile/src/pages/MyProfile/index.tsx
2025-06-08 19:08:41 +08:00

343 lines
11 KiB
TypeScript

// REQ0053/profile-page
//
// PURPOSE:
// - Provides functionality view user profile
//
// RULES:
// - T.B.A.
//
import React, { useEffect, useRef, useState } from 'react';
import {
IonHeader,
IonToolbar,
IonTitle,
IonContent,
IonPage,
IonButtons,
IonMenuButton,
IonGrid,
IonRow,
IonCol,
useIonRouter,
IonButton,
IonIcon,
IonPopover,
IonAvatar,
IonImg,
IonItem,
IonLabel,
IonList,
IonModal,
IonSearchbar,
useIonModal,
IonInput,
RefresherEventDetail,
IonRefresher,
IonRefresherContent,
} from '@ionic/react';
import SpeakerItem from '../../components/SpeakerItem';
import { Speaker } from '../../models/Speaker';
import { Session } from '../../models/Schedule';
import { connect } from '../../data/connect';
import * as selectors from '../../data/selectors';
import '../SpeakerList.scss';
import { getEvents } from '../../api/getEvents';
import { format } from 'date-fns';
import { Event } from './types';
import {
alertOutline,
chevronDownCircleOutline,
createOutline,
heart,
menuOutline,
settingsOutline,
} from 'ionicons/icons';
import AboutPopover from '../../components/AboutPopover';
import PATHS from '../../PATHS';
import { getProfileById } from '../../api/getProfileById';
import { defaultMember, Member } from '../MemberProfile/type';
import NotLoggedIn from './NotLoggedIn';
interface OwnProps {}
interface StateProps {
isLoggedin: boolean;
//
speakers: Speaker[];
speakerSessions: { [key: string]: Session[] };
}
interface DispatchProps {}
interface SpeakerListProps extends OwnProps, StateProps, DispatchProps {}
const MyProfilePage: React.FC<SpeakerListProps> = ({ speakers, speakerSessions, isLoggedin }) => {
if (!isLoggedin) return <NotLoggedIn />;
const [profile, setProfile] = useState<Member>(defaultMember);
const [showPopover, setShowPopover] = useState(false);
const [popoverEvent, setPopoverEvent] = useState<MouseEvent>();
const modal = useRef<HTMLIonModalElement>(null);
const router = useIonRouter();
function handleShowSettingButtonClick() {
router.push(PATHS.SETTINGS);
}
function handleNotImplementedClick() {
router.push(PATHS.NOT_IMPLEMENTED);
}
function handleRefresh(event: CustomEvent<RefresherEventDetail>) {
setTimeout(() => {
// Any calls to load data go here
event.detail.complete();
}, 2000);
}
useEffect(() => {
getProfileById('2').then(({ data }) => {
console.log({ data });
setProfile(data);
});
}, []);
if (!profile) return <>loading</>;
return (
<IonPage id="speaker-list">
<IonHeader translucent={true} className="ion-no-border">
<IonToolbar>
<IonButtons slot="end">
{/* <IonMenuButton /> */}
<IonButton shape="round" onClick={() => handleShowSettingButtonClick()}>
<IonIcon slot="icon-only" icon={settingsOutline}></IonIcon>
</IonButton>
</IonButtons>
<IonTitle>My profile</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen={true}>
<IonRefresher slot="fixed" onIonRefresh={handleRefresh}>
<IonRefresherContent
pullingIcon={chevronDownCircleOutline}
pullingText="Pull to refresh"
refreshingSpinner="circles"
refreshingText="Refreshing..."
></IonRefresherContent>
</IonRefresher>
<IonHeader collapse="condense" className="ion-no-border">
<IonToolbar>
<IonTitle size="large">My profile</IonTitle>
</IonToolbar>
</IonHeader>
<IonList lines="none">
<IonItem>
<div
style={{
marginTop: '1rem',
border: '1px solid lightgray',
borderRadius: '1rem',
width: '100%',
}}
>
<div style={{ padding: '1rem', display: 'flex', gap: '1rem' }}>
<IonAvatar>
<img
alt="Silhouette of a person's head"
src="https://plus.unsplash.com/premium_photo-1683121126477-17ef068309bc"
/>
</IonAvatar>
<div style={{ flexGrow: 1 }}>
<div
style={{
//
display: 'flex',
gap: '1rem',
alignItems: 'center',
}}
>
<div style={{ fontSize: '1.2rem', fontWeight: 'bold' }}>{profile.name}</div>
<div style={{ fontSize: '0.8rem' }}>{profile.rank}</div>
<div style={{ fontSize: '0.8rem' }}>{profile.verified}</div>
</div>
</div>
<div>
<IonButton
shape="round"
fill="clear"
size="large"
onClick={handleNotImplementedClick}
>
<IonIcon slot="icon-only" icon={createOutline}></IonIcon>
</IonButton>
</div>
</div>
</div>
</IonItem>
<IonItem>
<div
style={{
marginTop: '3rem',
//
borderRadius: '1rem',
width: '100%',
backgroundColor: 'gold',
}}
>
<div
style={{
padding: '1rem',
display: 'flex',
flexDirection: 'column',
gap: '1rem',
}}
>
<div style={{ fontWeight: 'bold', fontSize: '1.1rem' }}>Membership</div>
<div>7 of the exclusive privileges</div>
<div>
<IonButton
expand="full"
shape="round"
size="large"
onClick={handleNotImplementedClick}
>
Unlock
</IonButton>
</div>
</div>
</div>
</IonItem>
<IonItem>
<div style={{ marginTop: '3rem' }}>
<div style={{ fontSize: '1.1rem', fontWeight: 'bold' }}>Privileges Unlocked</div>
<div
style={{
marginTop: '1rem',
display: 'flex',
flexDirection: 'column',
gap: '1rem',
fontSize: '1rem',
}}
>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ flexGrow: 1 }}>Unlock participant list</div>
<IonIcon icon={alertOutline}></IonIcon>
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ flexGrow: 1 }}>Exclusive vip logo</div>
<IonIcon icon={alertOutline}></IonIcon>
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ flexGrow: 1 }}>View visitors</div>
<IonIcon icon={alertOutline}></IonIcon>
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ flexGrow: 1 }}>Tips of message read</div>
<IonIcon icon={alertOutline}></IonIcon>
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ flexGrow: 1 }}>Voice and images transmission</div>
<IonIcon icon={alertOutline}></IonIcon>
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ flexGrow: 1 }}>Pinned to the top of nearby list every 24 hours</div>
<IonIcon icon={alertOutline}></IonIcon>
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ flexGrow: 1 }}>Unlimited chat</div>
<IonIcon icon={alertOutline}></IonIcon>
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ flexGrow: 1 }}>Filter verified users</div>
<IonIcon icon={alertOutline}></IonIcon>
</div>
</div>
</div>
</IonItem>
</IonList>
</IonContent>
{/* REQ0079/event-filter */}
<IonModal
ref={modal}
trigger="my-profile-open-modal"
initialBreakpoint={0.5}
breakpoints={[0, 0.25, 0.5, 0.75]}
>
<IonContent className="ion-padding">
<div
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
gap: '1rem',
}}
>
<div
style={{
textAlign: 'center',
fontWeight: '1rem',
fontSize: '1.5rem',
marginTop: '0.5rem',
marginBottom: '0.5rem',
}}
>
Filter
</div>
<div
style={{
textAlign: 'center',
fontWeight: '1rem',
marginTop: '0.5rem',
marginBottom: '0.5rem',
}}
>
Maximum number of participant
</div>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<IonButton shape="round">2-10</IonButton>
<IonButton shape="round">12-40</IonButton>
<IonButton shape="round">All</IonButton>
</div>
<div
style={{
textAlign: 'center',
fontWeight: '1rem',
marginTop: '0.5rem',
marginBottom: '0.5rem',
}}
>
Held date
</div>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<IonButton shape="round">Weekly</IonButton>
<IonButton shape="round">Monthly</IonButton>
<IonButton shape="round">All</IonButton>
</div>
<IonButton shape="round" style={{ marginTop: '1rem', marginBottom: '1rem' }}>
Apply
</IonButton>
</div>
</IonContent>
</IonModal>
</IonPage>
);
};
export default connect<OwnProps, StateProps, DispatchProps>({
mapStateToProps: (state) => ({
speakers: selectors.getSpeakers(state),
speakerSessions: selectors.getSpeakerSessions(state),
isLoggedin: state.user.isLoggedin,
}),
component: React.memo(MyProfilePage),
});