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:
@@ -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}>
|
||||
|
54
03_source/mobile/src/components/Map.tsx
Normal file
54
03_source/mobile/src/components/Map.tsx
Normal 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;
|
@@ -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>
|
||||
|
@@ -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={{
|
||||
|
@@ -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) {
|
||||
|
@@ -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)}
|
||||
|
@@ -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} —
|
||||
{session.timeEnd}:
|
||||
{session.timeStart}—
|
||||
{session.timeEnd}—
|
||||
{session.location}
|
||||
</p>
|
||||
</IonLabel>
|
||||
</IonItem>
|
||||
<IonItemOptions>
|
||||
{listType === 'favorites' ? (
|
||||
<IonItemOption
|
||||
color="danger"
|
||||
onClick={() => removeFavoriteSession('Remove Favorite')}
|
||||
>
|
||||
<IonItemOption color="danger" onClick={() => removeFavoriteSession('Remove Favorite')}>
|
||||
Remove
|
||||
</IonItemOption>
|
||||
) : (
|
||||
|
@@ -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')}>
|
||||
|
Reference in New Issue
Block a user