Update requirement files with new feature templates and fix backend API error message, along with mobile project config updates and documentation improvements

This commit is contained in:
louiscklaw
2025-06-13 12:11:47 +08:00
parent f23a6b7d9c
commit 346992d4ec
3102 changed files with 220182 additions and 2896 deletions

View File

@@ -16,22 +16,13 @@ const AboutPopover: React.FC<AboutPopoverProps> = ({ dismiss }) => {
<IonItem button onClick={() => close('https://ionicframework.com/docs')}>
<IonLabel>Learn Ionic</IonLabel>
</IonItem>
<IonItem
button
onClick={() => close('https://ionicframework.com/docs/react')}
>
<IonItem button onClick={() => close('https://ionicframework.com/docs/react')}>
<IonLabel>Documentation</IonLabel>
</IonItem>
<IonItem
button
onClick={() => close('https://showcase.ionicframework.com')}
>
<IonItem button onClick={() => close('https://showcase.ionicframework.com')}>
<IonLabel>Showcase</IonLabel>
</IonItem>
<IonItem
button
onClick={() => close('https://github.com/ionic-team/ionic-framework')}
>
<IonItem button onClick={() => close('https://github.com/ionic-team/ionic-framework')}>
<IonLabel>GitHub Repo</IonLabel>
</IonItem>
<IonItem button onClick={dismiss}>

View File

@@ -0,0 +1,54 @@
import React, { useRef, useEffect } from 'react';
import { Location } from '../models/Location';
interface MapProps {
locations: Location[];
mapCenter: Location;
}
const Map: React.FC<MapProps> = ({ mapCenter, locations }) => {
const mapEle = useRef<HTMLDivElement>(null);
const map = useRef<google.maps.Map>();
useEffect(() => {
if (mapEle.current) {
map.current = new google.maps.Map(mapEle.current, {
center: {
lat: mapCenter.lat,
lng: mapCenter.lng,
},
zoom: 16,
});
addMarkers();
google.maps.event.addListenerOnce(map.current, 'idle', () => {
if (mapEle.current) {
mapEle.current.classList.add('show-map');
}
});
function addMarkers() {
locations.forEach((markerData) => {
let infoWindow = new google.maps.InfoWindow({
content: `<h5>${markerData.name}</h5>`,
});
let marker = new google.maps.Marker({
position: new google.maps.LatLng(markerData.lat, markerData.lng),
map: map.current!,
title: markerData.name,
});
marker.addListener('click', () => {
infoWindow.open(map.current!, marker);
});
});
}
}
}, [mapCenter, locations]);
return <div ref={mapEle} className="map-canvas"></div>;
};
export default Map;

View File

@@ -86,9 +86,7 @@ const Menu: React.FC<MenuProps> = ({
detail={false}
routerLink={p.path}
routerDirection="none"
className={
location.pathname.startsWith(p.path) ? 'selected' : undefined
}
className={location.pathname.startsWith(p.path) ? 'selected' : undefined}
>
<IonIcon slot="start" icon={p.icon} />
<IonLabel>{p.title}</IonLabel>
@@ -110,15 +108,8 @@ const Menu: React.FC<MenuProps> = ({
? renderlistItems(routes.loggedInPages)
: renderlistItems(routes.loggedOutPages)}
<IonItem>
<IonIcon
slot="start"
icon={moonOutline}
aria-hidden="true"
></IonIcon>
<IonToggle
checked={darkMode}
onClick={() => setDarkMode(!darkMode)}
>
<IonIcon slot="start" icon={moonOutline} aria-hidden="true"></IonIcon>
<IonToggle checked={darkMode} onClick={() => setDarkMode(!darkMode)}>
Dark Mode
</IonToggle>
</IonItem>

View File

@@ -4,8 +4,8 @@ import React, { CSSProperties, useState } from 'react';
import { connect } from '../../data/connect';
import { IonIcon, IonLoading } from '@ionic/react';
import { GridLoader } from 'react-spinners';
import { alertCircleOutline } from 'ionicons/icons';
import AlertSvg from './alert-svgrepo-com.svg';
import { alertCircleOutline, alertOutline } from 'ionicons/icons';
// import AlertSvg from './alert-svgrepo-com.svg';
interface OwnProps {}
@@ -42,7 +42,8 @@ function NoSavedEvents() {
gap: '3rem',
}}
>
<div style={{ backgroundImage: `url("${AlertSvg}")`, backgroundSize: 'contain', width: '100px', height: '100px', backgroundPosition: 'center' }}></div>
{/* TODO: alert icon modified from svg to IonIcon for build, need fallback */}
<IonIcon icon={alertOutline} />
<div
style={{

View File

@@ -42,19 +42,14 @@ const SessionList: React.FC<SessionListProps> = ({
const [showAlert, setShowAlert] = useState(false);
const [alertHeader, setAlertHeader] = useState('');
const [alertMessage, setAlertMessage] = useState('');
const [alertButtons, setAlertButtons] = useState<(AlertButton | string)[]>(
[]
);
const [alertButtons, setAlertButtons] = useState<(AlertButton | string)[]>([]);
const handleShowAlert = useCallback(
(header: string, message: string, buttons: AlertButton[]) => {
setAlertHeader(header);
setAlertMessage(message);
setAlertButtons(buttons);
setShowAlert(true);
},
[]
);
const handleShowAlert = useCallback((header: string, message: string, buttons: AlertButton[]) => {
setAlertHeader(header);
setAlertMessage(message);
setAlertButtons(buttons);
setShowAlert(true);
}, []);
useEffect(() => {
if (scheduleListRef.current) {

View File

@@ -112,12 +112,7 @@ const SessionListFilter: React.FC<SessionListFilterProps> = ({
{allTracks.map((track) => (
<IonItem key={track}>
{ios && (
<IonIcon
slot="start"
icon={iconMap[track]}
color="medium"
aria-hidden="true"
/>
<IonIcon slot="start" icon={iconMap[track]} color="medium" aria-hidden="true" />
)}
<IonCheckbox
onIonChange={() => toggleTrackFilter(track)}

View File

@@ -15,11 +15,7 @@ interface SessionListItemProps {
listType: 'all' | 'favorites';
onAddFavorite: (id: number) => void;
onRemoveFavorite: (id: number) => void;
onShowAlert: (
header: string,
message: string,
buttons: AlertButton[]
) => void;
onShowAlert: (header: string, message: string, buttons: AlertButton[]) => void;
isFavorite: boolean;
}
@@ -40,23 +36,19 @@ const SessionListItem: React.FC<SessionListItemProps> = ({
const removeFavoriteSession = (title: string) => {
onAddFavorite(session.id);
onShowAlert(
title,
'Would you like to remove this session from your favorites?',
[
{
text: 'Cancel',
handler: dismissAlert,
onShowAlert(title, 'Would you like to remove this session from your favorites?', [
{
text: 'Cancel',
handler: dismissAlert,
},
{
text: 'Remove',
handler: () => {
onRemoveFavorite(session.id);
dismissAlert();
},
{
text: 'Remove',
handler: () => {
onRemoveFavorite(session.id);
dismissAlert();
},
},
]
);
},
]);
};
const addFavoriteSession = async () => {
@@ -85,26 +77,20 @@ const SessionListItem: React.FC<SessionListItemProps> = ({
};
return (
<IonItemSliding
ref={ionItemSlidingRef}
class={'track-' + session.tracks[0].toLowerCase()}
>
<IonItemSliding ref={ionItemSlidingRef} class={'track-' + session.tracks[0].toLowerCase()}>
<IonItem routerLink={`/tabs/schedule/${session.id}`}>
<IonLabel>
<h3>{session.name}</h3>
<p>
{session.timeStart} &mdash;&nbsp;
{session.timeEnd}:&nbsp;
{session.timeStart}&mdash;&nbsp;
{session.timeEnd}&mdash;&nbsp;
{session.location}
</p>
</IonLabel>
</IonItem>
<IonItemOptions>
{listType === 'favorites' ? (
<IonItemOption
color="danger"
onClick={() => removeFavoriteSession('Remove Favorite')}
>
<IonItemOption color="danger" onClick={() => removeFavoriteSession('Remove Favorite')}>
Remove
</IonItemOption>
) : (

View File

@@ -1,17 +1,5 @@
import {
IonLoading,
IonFab,
IonFabButton,
IonIcon,
IonFabList,
} from '@ionic/react';
import {
shareSocial,
logoVimeo,
logoInstagram,
logoTwitter,
logoFacebook,
} from 'ionicons/icons';
import { IonLoading, IonFab, IonFabButton, IonIcon, IonFabList } from '@ionic/react';
import { shareSocial, logoVimeo, logoInstagram, logoTwitter, logoFacebook } from 'ionicons/icons';
import React, { useState } from 'react';
const ShareSocialFab: React.FC = () => {
@@ -40,10 +28,7 @@ const ShareSocialFab: React.FC = () => {
<IonFabButton color="vimeo" onClick={() => openSocial('Vimeo')}>
<IonIcon icon={logoVimeo} />
</IonFabButton>
<IonFabButton
color="instagram"
onClick={() => openSocial('Instagram')}
>
<IonFabButton color="instagram" onClick={() => openSocial('Instagram')}>
<IonIcon icon={logoInstagram} />
</IonFabButton>
<IonFabButton color="twitter" onClick={() => openSocial('Twitter')}>