init commit,

This commit is contained in:
louiscklaw
2025-05-28 09:55:51 +08:00
commit efe70ceb69
8042 changed files with 951668 additions and 0 deletions

View File

@@ -0,0 +1,227 @@
// REQ0041/home_discover_event_tab
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,
IonRefresher,
IonRefresherContent,
RefresherEventDetail,
IonToast,
useIonToast,
} 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 {
checkmarkOutline,
chevronBackOutline,
chevronDownCircleOutline,
closeOutline,
heart,
menuOutline,
} from 'ionicons/icons';
import AboutPopover from '../../components/AboutPopover';
import Loading from '../../components/Loading';
interface OwnProps {}
interface StateProps {
events: Event[];
}
interface DispatchProps {}
interface SpeakerListProps extends OwnProps, StateProps, DispatchProps {}
const EventList: React.FC<SpeakerListProps> = ({ events }) => {
const modal = useRef<HTMLIonModalElement>(null);
const router = useIonRouter();
function handleShowPartyEventDetail(event_id: string) {
router.push(`/event_detail/${event_id}`);
}
function handleRefresh(event: CustomEvent<RefresherEventDetail>) {
setTimeout(() => {
// Any calls to load data go here
event.detail.complete();
}, 2000);
}
const [confirmChangeLanguage, setConfirmChangeLanguage] =
useState<boolean>(false);
function handleChangeToChinese() {
setConfirmChangeLanguage(true);
}
function handleChangeToEnglish() {
setConfirmChangeLanguage(true);
}
function handleChangeToJapanese() {
setConfirmChangeLanguage(true);
}
function handleApplyChangeLanguage() {
setConfirmChangeLanguage(false);
}
function handleBackClick() {
router.goBack();
}
function handleCancelChangeLanguage() {
setConfirmChangeLanguage(false);
}
const [present] = useIonToast();
const presentToast = () => {
present({
message: 'sorry but the function not yet implemented!',
duration: 1500,
position: 'bottom',
});
setConfirmChangeLanguage(false);
};
if (!events || events.length == 0) return <Loading />;
return (
<IonPage id="speaker-list">
<IonHeader translucent={true}>
<IonToolbar>
<IonButtons slot="start" onClick={handleBackClick}>
{/* <IonMenuButton /> */}
<IonButton shape="round" id="open-modal" expand="block">
<IonIcon slot="icon-only" icon={chevronBackOutline}></IonIcon>
</IonButton>
</IonButtons>
<IonTitle>Change Language</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen={true}>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Change Language</IonTitle>
</IonToolbar>
</IonHeader>
<IonList>
<IonItem button={true} onClick={handleChangeToChinese}>
<IonLabel>Chinese</IonLabel>
</IonItem>
<IonItem button={true} onClick={handleChangeToEnglish}>
<IonLabel>English</IonLabel>
</IonItem>
<IonItem button={true} onClick={handleChangeToJapanese}>
<IonLabel>Japanese</IonLabel>
</IonItem>
</IonList>
</IonContent>
{/* REQ0079/event-filter */}
<IonModal
ref={modal}
isOpen={confirmChangeLanguage}
initialBreakpoint={0.33}
breakpoints={[0, 0.33, 0.66]}
onDidDismiss={() => setConfirmChangeLanguage(false)}
>
<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',
}}
>
Confirm change language
</div>
<div
style={{
textAlign: 'center',
fontWeight: '1rem',
marginTop: '0.5rem',
marginBottom: '0.5rem',
}}
>
Change language to Chinese
</div>
<div
style={{
marginLeft: '1rem',
marginRight: '1rem',
display: 'flex',
justifyContent: 'space-between',
}}
>
<IonButton
fill="outline"
size="large"
shape="round"
onClick={handleCancelChangeLanguage}
>
<IonIcon slot="start" icon={closeOutline}></IonIcon>
No
</IonButton>
<IonButton size="large" shape="round" onClick={presentToast}>
<IonIcon slot="start" icon={checkmarkOutline}></IonIcon>
Yes
</IonButton>
</div>
</div>
</IonContent>
</IonModal>
</IonPage>
);
};
export default connect<OwnProps, StateProps, DispatchProps>({
mapStateToProps: (state) => ({
events: selectors.getEvents(state),
}),
component: React.memo(EventList),
});

View File

@@ -0,0 +1,110 @@
import {
IonButton,
IonButtons,
IonContent,
IonHeader,
IonIcon,
IonPage,
IonTitle,
IonToolbar,
useIonRouter,
} from '@ionic/react';
import { chevronBackOutline, settingsOutline } from 'ionicons/icons';
import React from 'react';
import { createRoot } from 'react-dom/client';
import Markdown from 'react-markdown';
const markdown = `
# 服務協議及社區規範
歡迎使用香港單身派對!本服務協議及社區規範(以下簡稱“協議”)旨在規範您使用香港單身派對(以下簡稱“平台”)的行為,確保平台的健康運營和用戶的良好體驗。請在使用平台前仔細閱讀並遵守本協議。
1. 服務內容
香港單身派對提供以下服務:
(a) 附近的人交友:使用地理定位功能幫助您認識附近的用戶。
(b) 線上活動參與:平台不定期舉辦各類線上活動,包括但不限於遊戲配對、主題討論和社交聚會。
2. 用戶權利與義務
(a) 用戶有權使用平台提供的服務,並參與平台組織的活動。
(b) 用戶應確保其在平台上發布的個人照片及資料真實且屬於本人,不得使用他人的照片或虛假信息。
(c) 用戶應遵守相關法律法規,不得利用平台進行任何非法活動。
(d) 用戶應尊重其他用戶的隱私權和個人信息安全,不得收集、使用或披露其他用戶的信息。
(e) 用戶應維護良好的社區環境,不得發布任何違背公序良俗、含有歧視、騷擾、暴力或色情等內容的信息。
(f) 用戶不得抄襲、模仿或以其他方式侵犯平台的知識產權,包括但不限於應用程序的界面設計、功能實現和內容創作。
(g) 本平台僅限於 18 歲以上的用戶使用。未滿 18 歲的用戶不得使用平台,一旦發現,其帳號將被終止。
3. 社區規範
(a) 禁止發布任何形式的廣告、垃圾信息或欺詐信息。
(b) 用戶應保持友好互動,避免使用侮辱性、攻擊性的語言。
(c) 用戶不得發布、傳播任何侵犯他人知識產權或其他合法權益的信息。
(d) 用戶應遵守平台的操作規範,不得進行任何破壞平台正常運行的行為。
4. 隱私保護
平台將採取合理措施保護用戶的個人信息,並遵守相關隱私保護法律法規。用戶同意平台在提供服務過程中收集和使用其個人信息。
5. 違規處理
用戶違反本協議時,平台將視情節輕重給予警告或終止其帳號的使用權。嚴重違反者將被永久禁止使用平台服務。
6. 協議的變更與終止
(a) 平台有權根據需要對本協議進行修改,並在平台上公佈最新版本。
(b) 如用戶違反本協議,平台有權限制或終止其使用平台的權利。
7. 爭議解決
因本協議引起的任何爭議,雙方應首先嘗試友好協商解決;協商不成時,任何一方可直接提出訴訟。
8. 其他
(a) 本平台保留對所有情況的最終決定權和解釋權。
(b) 本協議的附件是協議不可分割的一部分,與協議具有同等法律效力。
用戶在使用平台服務時,即表示已閱讀、理解並同意遵守本協議。
`;
function ServiceAgreement() {
const router = useIonRouter();
function handleBackButtonClick() {
router.goBack();
}
return (
<IonPage id="speaker-list">
<IonHeader translucent={true} className="ion-no-border">
<IonToolbar>
<IonButtons slot="start">
{/* <IonMenuButton /> */}
<IonButton shape="round" onClick={() => handleBackButtonClick()}>
<IonIcon slot="icon-only" icon={chevronBackOutline}></IonIcon>
</IonButton>
</IonButtons>
<IonTitle>Service Agreement</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen={true}>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Service Agreement</IonTitle>
</IonToolbar>
</IonHeader>
<div style={{ paddingLeft: '10px', paddingRight: '10px' }}>
<Markdown>{markdown}</Markdown>
<div
style={{
height: '7rem',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}
>
<div>end</div>
</div>
</div>
</IonContent>
</IonPage>
);
}
export default ServiceAgreement;

View File

@@ -0,0 +1,103 @@
#about-page {
ion-toolbar {
position: absolute;
top: 0;
left: 0;
right: 0;
--background: transparent;
--color: white;
}
ion-toolbar ion-back-button,
ion-toolbar ion-button,
ion-toolbar ion-menu-button {
--color: white;
}
.about-header {
position: relative;
width: 100%;
height: 30%;
}
.about-header .about-image {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
opacity: 0;
transition: opacity 500ms ease-in-out;
}
.about-header .madison {
background-image: url('/assets/img/about/madison.jpg');
}
.about-header .austin {
background-image: url('/assets/img/about/austin.jpg');
}
.about-header .chicago {
background-image: url('/assets/img/about/chicago.jpg');
}
.about-header .seattle {
background-image: url('/assets/img/about/seattle.jpg');
}
.about-info {
position: relative;
margin-top: -10px;
border-radius: 10px;
background: var(--ion-background-color, #fff);
z-index: 2; // display rounded border above header image
}
.about-info h3 {
margin-top: 0;
}
.about-info ion-list {
padding-top: 0;
}
.about-info p {
line-height: 130%;
color: var(--ion-color-dark);
}
.about-info ion-icon {
margin-inline-end: 32px;
}
/*
* iOS Only
*/
.ios .about-info {
--ion-padding: 19px;
}
.ios .about-info h3 {
font-weight: 700;
}
}
#date-input-popover {
--offset-y: -var(--ion-safe-area-bottom);
--max-width: 90%;
--width: 336px;
}