feat: add comprehensive ServiceMenu and MainTabs components with hotel service listings, QR code access, and user profile settings integration
@@ -63,10 +63,18 @@ import { format, parseISO } from 'date-fns';
|
||||
// import lookForVisitorSvg from './look_for_visitor.svg';
|
||||
|
||||
const SellingButton: React.FC = () => {
|
||||
const router = useIonRouter();
|
||||
return (
|
||||
<>
|
||||
<div style={{ width: '50%' }}>
|
||||
<IonCard style={{ margin: '0.5rem' }} button onClick={(e) => console.log('helloworld')}>
|
||||
<IonCard
|
||||
style={{ margin: '0.5rem' }}
|
||||
button
|
||||
onClick={(e) => {
|
||||
window.location.href =
|
||||
'https://www.carousell.com.hk/p/coding-javascript-python-vba-freelance-1192889425/';
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="Silhouette of mountains"
|
||||
src="https://ionicframework.com/docs/img/demos/card-media.png"
|
||||
@@ -127,17 +135,12 @@ const ListingsContent: React.FC<SessionListProps> = ({ hide }) => {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-evenly',
|
||||
justifyContent: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<SellingButton />
|
||||
<SellingButton />
|
||||
<SellingButton />
|
||||
<SellingButton />
|
||||
<SellingButton />
|
||||
<SellingButton />
|
||||
<SellingButton />
|
||||
<SellingButton />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
@@ -34,7 +34,9 @@ import {
|
||||
IonSegmentButton,
|
||||
useIonRouter,
|
||||
} from '@ionic/react';
|
||||
|
||||
import './style.scss';
|
||||
|
||||
import {
|
||||
locationSharp,
|
||||
settingsOutline,
|
||||
@@ -56,6 +58,9 @@ import {
|
||||
heartSharp,
|
||||
heartOutline,
|
||||
chatbubblesOutline,
|
||||
heart,
|
||||
chatbubbles,
|
||||
chatbox,
|
||||
} from 'ionicons/icons';
|
||||
import AboutPopover from '../../components/AboutPopover';
|
||||
import { format, parseISO } from 'date-fns';
|
||||
@@ -67,8 +72,13 @@ import ReviewsContent from './ReviewsContent';
|
||||
import ListingsContent from './ListingsContent';
|
||||
import { triggerShare } from '../../util/triggerShare';
|
||||
import { connect } from '../../data/connect';
|
||||
import PATHS from '../../PATHS';
|
||||
// import { toProperCase } from 'src/util/toProperCase';
|
||||
|
||||
import './theme/variables.scss';
|
||||
import { messages } from '../DemoFacebookClone/main/messages';
|
||||
import { Router } from 'react-router';
|
||||
|
||||
interface OwnProps {}
|
||||
|
||||
interface StateProps {
|
||||
@@ -133,16 +143,43 @@ const CarousellMe: React.FC<CarousellMeProps> = () => {
|
||||
<IonToolbar>
|
||||
<IonButtons slot="end">
|
||||
<IonButton onClick={presentPopover}>
|
||||
<IonIcon slot="icon-only" icon={heartOutline}></IonIcon>
|
||||
<div>
|
||||
<IonIcon slot="icon-only" icon={heartOutline} size="large"></IonIcon>
|
||||
</div>
|
||||
</IonButton>
|
||||
<IonButton onClick={presentPopover}>
|
||||
<IonIcon slot="icon-only" icon={chatbubblesOutline}></IonIcon>
|
||||
<IonBadge style={{ backgroundColor: 'white', color: 'black' }}>1</IonBadge>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<IonIcon slot="icon-only" icon={chatbox} size="large"></IonIcon>
|
||||
|
||||
<div
|
||||
style={{
|
||||
color: 'black',
|
||||
fontWeight: 'bold',
|
||||
//
|
||||
position: 'relative',
|
||||
height: 0,
|
||||
top: '-1.5rem',
|
||||
//
|
||||
fontSize: '0.8rem',
|
||||
}}
|
||||
>
|
||||
<div>99</div>
|
||||
</div>
|
||||
</div>
|
||||
</IonButton>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
|
||||
{/* */}
|
||||
{/* */}
|
||||
{/* */}
|
||||
<div className="about-header">
|
||||
{/* Instead of loading an image each time the select changes, use opacity to transition them */}
|
||||
<div
|
||||
@@ -153,19 +190,18 @@ const CarousellMe: React.FC<CarousellMeProps> = () => {
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '1.5rem',
|
||||
gap: '0.5rem',
|
||||
paddingLeft: '1rem',
|
||||
paddingRight: '1rem',
|
||||
}}
|
||||
>
|
||||
<div className="profile-test">
|
||||
<img
|
||||
src="https://avatars.githubusercontent.com/u/1376093"
|
||||
src="https://media.karousell.com/media/photos/profiles/2025/02/05/louis_coding_1738774979_f1598e0b.jpg"
|
||||
style={{
|
||||
height: '75px',
|
||||
width: '75px',
|
||||
@@ -175,7 +211,7 @@ const CarousellMe: React.FC<CarousellMeProps> = () => {
|
||||
/>
|
||||
|
||||
<div className="setting-icons">
|
||||
<IonButton fill="clear" onClick={handleShareLink}>
|
||||
<IonButton shape="round" fill="clear" onClick={handleShareLink}>
|
||||
<IonIcon
|
||||
color="primary"
|
||||
slot="icon-only"
|
||||
@@ -184,13 +220,15 @@ const CarousellMe: React.FC<CarousellMeProps> = () => {
|
||||
></IonIcon>
|
||||
</IonButton>
|
||||
|
||||
<IonButton fill="clear" routerLink="/tabs/carousell_me/qr_page">
|
||||
<IonButton shape="round" fill="clear" routerLink={PATHS.CAROUSELL_ME_QR}>
|
||||
<IonIcon color="primary" slot="icon-only" ios={qrCode} md={qrCode}></IonIcon>
|
||||
</IonButton>
|
||||
|
||||
<IonButton
|
||||
shape="round"
|
||||
fill="clear"
|
||||
routerLink="/tabs/carousell_me/settings"
|
||||
routerLink={PATHS.CAROUSELL_ME_SETTINGS}
|
||||
// onClick={() => route.push(PATHS.CAROUSELL_ME_SETTINGS, 'forward', 'push')}
|
||||
// onClick={handleSettingPageClick}
|
||||
>
|
||||
<IonIcon
|
||||
@@ -203,8 +241,8 @@ const CarousellMe: React.FC<CarousellMeProps> = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
|
||||
<div style={{ fontWeight: 'bold' }}>Louis Law</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem' }}>
|
||||
<div style={{ fontWeight: 'bold' }}>louis_coding</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: '0.9rem',
|
||||
@@ -213,7 +251,7 @@ const CarousellMe: React.FC<CarousellMeProps> = () => {
|
||||
gap: '0.8rem',
|
||||
}}
|
||||
>
|
||||
<IonText color="medium">@louiscklaw</IonText>
|
||||
<IonText color="medium">@louis_coding</IonText>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
@@ -321,7 +359,6 @@ const CarousellMe: React.FC<CarousellMeProps> = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* listing / reviews / about */}
|
||||
<IonSegment
|
||||
mode={'md'}
|
||||
@@ -333,7 +370,6 @@ const CarousellMe: React.FC<CarousellMeProps> = () => {
|
||||
<IonSegmentButton value="about">{t('About')}</IonSegmentButton>
|
||||
</IonSegment>
|
||||
{/* listing / reviews / about */}
|
||||
|
||||
<ListingsContent hide={segment != 'listings'} />
|
||||
<ReviewsContent hide={segment != 'reviews'} />
|
||||
<AboutContent hide={segment != 'about'} />
|
||||
|
@@ -1,7 +1,13 @@
|
||||
#carousell-me-page {
|
||||
--ion-color-tertiary: #ad8e70;
|
||||
--ion-color-tertiary-rgb: 173, 142, 112;
|
||||
--ion-color-tertiary-contrast: #000000;
|
||||
--ion-color-tertiary-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-tertiary-shade: #987d63;
|
||||
--ion-color-tertiary-tint: #b5997e;
|
||||
|
||||
.setting-icons {
|
||||
ion-button::part(native) {
|
||||
// https://ionicframework.com/docs/theming/css-shadow-parts
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
59
03_source/mobile/src/pages/CarousellMe/theme/variables.scss
Normal file
@@ -0,0 +1,59 @@
|
||||
#carousell-me-page {
|
||||
ion-button {
|
||||
--ion-color-primary: #243763;
|
||||
--ion-color-primary-rgb: 36, 55, 99;
|
||||
--ion-color-primary-contrast: #ffffff;
|
||||
--ion-color-primary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-primary-shade: #203057;
|
||||
--ion-color-primary-tint: #3a4b73;
|
||||
|
||||
--ion-color-secondary: #ff6e31;
|
||||
--ion-color-secondary-rgb: 255, 110, 49;
|
||||
--ion-color-secondary-contrast: #000000;
|
||||
--ion-color-secondary-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-secondary-shade: #e0612b;
|
||||
--ion-color-secondary-tint: #ff7d46;
|
||||
|
||||
--ion-color-tertiary: #ad8e70;
|
||||
--ion-color-tertiary-rgb: 173, 142, 112;
|
||||
--ion-color-tertiary-contrast: #000000;
|
||||
--ion-color-tertiary-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-tertiary-shade: #987d63;
|
||||
--ion-color-tertiary-tint: #b5997e;
|
||||
|
||||
--ion-color-success: #2dd36f;
|
||||
--ion-color-success-rgb: 45, 211, 111;
|
||||
--ion-color-success-contrast: #000000;
|
||||
--ion-color-success-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-success-shade: #28ba62;
|
||||
--ion-color-success-tint: #42d77d;
|
||||
|
||||
--ion-color-warning: #ffc409;
|
||||
--ion-color-warning-rgb: 255, 196, 9;
|
||||
--ion-color-warning-contrast: #000000;
|
||||
--ion-color-warning-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-warning-shade: #e0ac08;
|
||||
--ion-color-warning-tint: #ffca22;
|
||||
|
||||
--ion-color-danger: #eb445a;
|
||||
--ion-color-danger-rgb: 235, 68, 90;
|
||||
--ion-color-danger-contrast: #ffffff;
|
||||
--ion-color-danger-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-danger-shade: #cf3c4f;
|
||||
--ion-color-danger-tint: #ed576b;
|
||||
|
||||
--ion-color-medium: #92949c;
|
||||
--ion-color-medium-rgb: 146, 148, 156;
|
||||
--ion-color-medium-contrast: #000000;
|
||||
--ion-color-medium-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-medium-shade: #808289;
|
||||
--ion-color-medium-tint: #9d9fa6;
|
||||
|
||||
--ion-color-light: #ffebb7;
|
||||
--ion-color-light-rgb: 255, 235, 183;
|
||||
--ion-color-light-contrast: #000000;
|
||||
--ion-color-light-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-light-shade: #e0cfa1;
|
||||
--ion-color-light-tint: #ffedbe;
|
||||
}
|
||||
}
|
@@ -1,98 +0,0 @@
|
||||
// REQ0116/main-tab
|
||||
|
||||
import React from 'react';
|
||||
import { IonTabs, IonRouterOutlet, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/react';
|
||||
import { Route, Redirect } from 'react-router';
|
||||
import { calendar, location, informationCircle, people } from 'ionicons/icons';
|
||||
import SchedulePage from './SchedulePage';
|
||||
import SpeakerList from './SpeakerList';
|
||||
import SpeakerDetail from './SpeakerDetail';
|
||||
import SessionDetail from './SessionDetail';
|
||||
import MapView from './MapView';
|
||||
import About from './About';
|
||||
import EventList from './EventList';
|
||||
import MembersNearByList from './MembersNearByList';
|
||||
import OrderList from './OrderList';
|
||||
import MyProfile from './MyProfile';
|
||||
import MessageList from './MessageList';
|
||||
import PATHS from '../PATHS';
|
||||
import Favourites from './Favourites';
|
||||
import Helloworld from './Helloworld';
|
||||
import TabAppRoute from '../TabAppRoute';
|
||||
import CarousellMe from './CarousellMe';
|
||||
|
||||
interface MainTabsProps {}
|
||||
|
||||
const MainTabs: React.FC<MainTabsProps> = () => {
|
||||
return (
|
||||
<IonTabs>
|
||||
<IonRouterOutlet>
|
||||
{/* REQ0117/default-route */}
|
||||
<Redirect exact path="/tabs" to="/tabs/events" />
|
||||
{/*
|
||||
Using the render method prop cuts down the number of renders your components will have due to route changes.
|
||||
Use the component prop when your component depends on the RouterComponentProps passed in automatically.
|
||||
*/}
|
||||
<Route path="/tabs/schedule" render={() => <SchedulePage />} exact={true} />
|
||||
<Route path="/tabs/speakers" render={() => <SpeakerList />} exact={true} />
|
||||
<Route path="/tabs/speakers/:id" component={SpeakerDetail} exact={true} />
|
||||
|
||||
<Route path="/tabs/schedule/:id" component={SessionDetail} />
|
||||
<Route path="/tabs/speakers/sessions/:id" component={SessionDetail} />
|
||||
<Route path="/tabs/map" render={() => <MapView />} exact={true} />
|
||||
|
||||
<Route path="/tabs/about" render={() => <About />} exact={true} />
|
||||
<Route path="/tabs/helloworld" render={() => <Helloworld />} exact={true} />
|
||||
|
||||
{/* */}
|
||||
<Route path={PATHS.CAROUSELL_ME} render={() => <CarousellMe />} exact={true} />
|
||||
{/*
|
||||
<Route path="/tabs/carousell_me/insights" component={Insights} exact={true} />
|
||||
<Route path="/tabs/carousell_me/OffersMade" component={OffersMade} exact={true} />
|
||||
<Route path="/tabs/carousell_me/settings" component={Settings} exact={true} />
|
||||
<Route path="/tabs/carousell_me/my_profile" component={MyProfile} exact={true} />
|
||||
<Route path="/tabs/carousell_me/qr_page" component={QRPage} exact={true} />
|
||||
*/}
|
||||
|
||||
{/* */}
|
||||
<TabAppRoute />
|
||||
</IonRouterOutlet>
|
||||
{/* */}
|
||||
<IonTabBar slot="bottom">
|
||||
{/*
|
||||
<IonTabButton tab="speakers" href={'/tabs/speakers'}>
|
||||
<IonIcon icon={calendar} />
|
||||
<IonLabel>Speakers</IonLabel>
|
||||
</IonTabButton>
|
||||
*/}
|
||||
|
||||
<IonTabButton tab="events" href={PATHS.EVENT_LIST}>
|
||||
<IonIcon icon={calendar} />
|
||||
<IonLabel>Event</IonLabel>
|
||||
</IonTabButton>
|
||||
<IonTabButton tab="nearby" href={PATHS.NEARBY_LIST}>
|
||||
<IonIcon icon={people} />
|
||||
<IonLabel>Nearby</IonLabel>
|
||||
</IonTabButton>
|
||||
{/*
|
||||
<IonTabButton tab="orders" href={PATHS.ORDERS_LIST}>
|
||||
<IonIcon icon={location} />
|
||||
<IonLabel>Order</IonLabel>
|
||||
</IonTabButton>
|
||||
*/}
|
||||
<IonTabButton disabled></IonTabButton>
|
||||
|
||||
<IonTabButton tab="message" href={PATHS.MESSAGE_LIST}>
|
||||
<IonIcon icon={informationCircle} />
|
||||
<IonLabel>Message</IonLabel>
|
||||
</IonTabButton>
|
||||
<IonTabButton tab="my_profile" href={PATHS.PROFILE}>
|
||||
<IonIcon icon={informationCircle} />
|
||||
<IonLabel>Profile</IonLabel>
|
||||
</IonTabButton>
|
||||
</IonTabBar>
|
||||
</IonTabs>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainTabs;
|
34
03_source/mobile/src/pages/MainTabs/MenuButton.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { IonCard, IonImg } from '@ionic/react';
|
||||
import React from 'react';
|
||||
|
||||
interface MenuButtonProps {
|
||||
iconUrl: string;
|
||||
buttonText: string;
|
||||
targetUrl: string;
|
||||
onClick: (e: React.UIEvent) => void;
|
||||
}
|
||||
|
||||
const MenuButton: React.FC<MenuButtonProps> = ({ iconUrl, buttonText, targetUrl, onClick }) => {
|
||||
return (
|
||||
<>
|
||||
<IonCard
|
||||
button
|
||||
href={targetUrl}
|
||||
className="service-button"
|
||||
style={{
|
||||
width: '24%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<IonImg src={iconUrl}></IonImg>
|
||||
<div style={{ fontSize: '0.8rem', textAlign: 'center' }}>{buttonText}</div>
|
||||
<div style={{ fontSize: '0.8rem', textAlign: 'center' }}>(附加費)</div>
|
||||
</IonCard>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(MenuButton);
|
135
03_source/mobile/src/pages/MainTabs/ServiceMenu.tsx
Normal file
@@ -0,0 +1,135 @@
|
||||
import {
|
||||
IonButton,
|
||||
IonButtons,
|
||||
IonContent,
|
||||
IonGrid,
|
||||
IonHeader,
|
||||
IonItem,
|
||||
IonModal,
|
||||
IonRow,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
useIonModal,
|
||||
} from '@ionic/react';
|
||||
import React, { useState } from 'react';
|
||||
import CloseButton from '../../components/CloseButton';
|
||||
import MenuButton from './MenuButton';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import './style.scss';
|
||||
|
||||
interface ServiceMenuProps {
|
||||
hotelServiceMenu: any;
|
||||
showCenterButton: boolean;
|
||||
buttonSvg: any;
|
||||
}
|
||||
|
||||
// bookmark: facilities, bottom drawer, ServiceMenu
|
||||
const ServiceMenu: React.FC<ServiceMenuProps> = ({
|
||||
buttonSvg,
|
||||
showCenterButton,
|
||||
hotelServiceMenu,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
|
||||
function dismiss() {
|
||||
setDrawerOpen(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonModal
|
||||
isOpen={drawerOpen}
|
||||
id="main-tabs-modal"
|
||||
style={{
|
||||
display: drawerOpen ? 'flex' : 'none',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
onWillDismiss={dismiss}
|
||||
>
|
||||
<div className="wrapper" style={{ paddingTop: '1rem', paddingBottom: '1rem' }}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<h6>{t('Greetings from xxx hotel')}</h6>
|
||||
<h4>{t('please enjoy our services')}</h4>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: '0.25rem',
|
||||
rowGap: '1rem',
|
||||
justifyContent: 'space-around',
|
||||
marginTop: '1rem',
|
||||
}}
|
||||
>
|
||||
{hotelServiceMenu.map((service: any, index: number) => (
|
||||
<MenuButton
|
||||
key={index}
|
||||
iconUrl={service.icon}
|
||||
buttonText={service.name}
|
||||
onClick={(e) => console.log('archive ?')}
|
||||
targetUrl={service.targetUrl}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<IonGrid>
|
||||
<IonRow class="ion-justify-content-center" style={{ marginTop: '2rem' }}>
|
||||
<IonItem button lines="none" onClick={dismiss}>
|
||||
<CloseButton onClick={(e) => dismiss()} />
|
||||
</IonItem>
|
||||
</IonRow>
|
||||
</IonGrid>
|
||||
</div>
|
||||
</IonModal>
|
||||
|
||||
{/* */}
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
zIndex: 102,
|
||||
//
|
||||
bottom: '20px',
|
||||
width: '50px',
|
||||
height: '50px',
|
||||
backgroundColor: 'gold',
|
||||
//
|
||||
borderRadius: '10px',
|
||||
left: 'calc( (100vw - 50px) / 2 )',
|
||||
//
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
//
|
||||
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2), 0 6px 20px rgba(0, 0, 0, 0.19)',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '80%',
|
||||
width: '80%',
|
||||
backgroundImage: `url("${buttonSvg}")`,
|
||||
backgroundPosition: 'center',
|
||||
backgroundSize: 'contain',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}}
|
||||
onClick={() => setDrawerOpen(true)}
|
||||
></div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ServiceMenu);
|
187
03_source/mobile/src/pages/MainTabs/index.tsx
Normal file
@@ -0,0 +1,187 @@
|
||||
// REQ0116/main-tab
|
||||
//
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { IonTabs, IonRouterOutlet, IonTabBar, IonTabButton, IonIcon, IonLabel, IonButton } from '@ionic/react';
|
||||
import { Route, Redirect } from 'react-router';
|
||||
import { calendar, location, informationCircle, people } from 'ionicons/icons';
|
||||
import SchedulePage from '../SchedulePage';
|
||||
import SpeakerList from '../SpeakerList';
|
||||
import SpeakerDetail from '../SpeakerDetail';
|
||||
import SessionDetail from '../SessionDetail';
|
||||
import MapView from '../MapView';
|
||||
import About from '../About';
|
||||
import EventList from '../EventList';
|
||||
import MembersNearByList from '../MembersNearByList';
|
||||
import OrderList from '../OrderList';
|
||||
import MyProfile from '../MyProfile';
|
||||
import MessageList from '../MessageList';
|
||||
import PATHS from '../../PATHS';
|
||||
import Favourites from '../Favourites';
|
||||
import Helloworld from '../Helloworld';
|
||||
import TabAppRoute from '../../TabAppRoute';
|
||||
import CarousellMe from '../CarousellMe';
|
||||
import ServiceMenu from './ServiceMenu';
|
||||
|
||||
//
|
||||
import QRPage from '../tabs/carousell_me/QRPage';
|
||||
|
||||
//
|
||||
import svgIcon1 from './icons/air-conditioning-cooling-heat-temperature-svgrepo-com.svg';
|
||||
import svgIcon2 from './icons/alert-attention-caution-dangerous-warning-svgrepo-com.svg';
|
||||
import svgIcon3 from './icons/alert-bell-call-message-sign-svgrepo-com.svg';
|
||||
import svgIcon4 from './icons/assistance-business-person-reception-service-svgrepo-com.svg';
|
||||
import svgIcon5 from './icons/bag-baggage-luggage-suitcase-travel-svgrepo-com.svg';
|
||||
import svgIcon6 from './icons/baggage-bellhop-hotel-service-waiter-svgrepo-com.svg';
|
||||
import svgIcon7 from './icons/bag-holiday-journey-suitcase-vacation-svgrepo-com.svg';
|
||||
import svgIcon8 from './icons/banking-financial-money-payment-transaction-svgrepo-com.svg';
|
||||
import svgIcon9 from './icons/bar-cafe-chair-club-stool-svgrepo-com.svg';
|
||||
import svgIcon10 from './icons/bath-bathroom-cotton-textile-towel-svgrepo-com.svg';
|
||||
import svgIcon11 from './icons/bathroom-bathtub-bubble-foam-water-svgrepo-com.svg';
|
||||
import svgIcon12 from './icons/bathroom-faucet-room-sink-wash-svgrepo-com.svg';
|
||||
import svgIcon13 from './icons/bed-furniture-interior-pillow-rest-2-svgrepo-com.svg';
|
||||
import svgIcon14 from './icons/bed-furniture-interior-pillow-rest-3-svgrepo-com.svg';
|
||||
import svgIcon15 from './icons/bed-furniture-interior-pillow-rest-svgrepo-com.svg';
|
||||
import svgIcon16 from './icons/book-catalog-document-guidebook-instruction-svgrepo-com.svg';
|
||||
import svgIcon17 from './icons/business-finance-money-saving-wallet-svgrepo-com.svg';
|
||||
import svgIcon18 from './icons/cafe-card-food-menu-vintage-svgrepo-com.svg';
|
||||
import svgIcon19 from './icons/cafe-cup-drink-mug-tea-svgrepo-com.svg';
|
||||
import svgIcon20 from './icons/calendar-date-day-month-time-svgrepo-com.svg';
|
||||
import svgIcon21 from './icons/cappuccino-coffee-cup-drink-espresso-2-svgrepo-com.svg';
|
||||
import svgIcon22 from './icons/cappuccino-coffee-cup-drink-espresso-svgrepo-com.svg';
|
||||
import svgIcon23 from './icons/card-credit-currency-finance-money-svgrepo-com.svg';
|
||||
import svgIcon24 from './icons/card-door-key-lock-security-svgrepo-com.svg';
|
||||
import svgIcon25 from './icons/chair-comfortable-decoration-garden-terrace-svgrepo-com.svg';
|
||||
import svgIcon26 from './icons/clean-clothing-laundry-washing-wind-svgrepo-com.svg';
|
||||
import svgIcon27 from './icons/comfortable-fabric-footwear-shoe-slipper-svgrepo-com.svg';
|
||||
import svgIcon28 from './icons/coupon-entertainment-event-paper-ticket-svgrepo-com.svg';
|
||||
import svgIcon29 from './icons/door-elevator-entrance-floor-lift-svgrepo-com.svg';
|
||||
import svgIcon30 from './icons/door-enter-entry-exit-open-svgrepo-com.svg';
|
||||
import svgIcon31 from './icons/door-entrance-handle-key-security-svgrepo-com.svg';
|
||||
import svgIcon32 from './icons/door-key-lock-room-security-svgrepo-com.svg';
|
||||
import svgIcon33 from './icons/electronic-internet-screen-technology-television-svgrepo-com.svg';
|
||||
import svgIcon34 from './icons/holiday-hotel-journey-service-travel-2-svgrepo-com.svg';
|
||||
import svgIcon35 from './icons/holiday-hotel-journey-service-travel-svgrepo-com.svg';
|
||||
import svgIcon36 from './icons/holiday-hotel-motel-sign-travel-svgrepo-com.svg';
|
||||
import svgIcon37 from './icons/holiday-journey-luggage-suitcase-vacation-2-svgrepo-com.svg';
|
||||
import svgIcon38 from './icons/hotel-location-map-pin-travel-svgrepo-com.svg';
|
||||
import getButtonSvg from '../../api/getButtonSvg';
|
||||
//
|
||||
|
||||
const hotelServiceMenu = [
|
||||
{ name: '停車場', icon: svgIcon1, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '接機服務', icon: svgIcon2, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '餐廳', icon: svgIcon3, targetUrl: '/tabs/hotel/:hotelid/restaurants' },
|
||||
{ name: '咖啡室', icon: svgIcon4, targetUrl: '/tabs/restaurant/:restaurant_id/food/:food_id/intro' },
|
||||
{ name: '酒吧', icon: svgIcon5, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '會議室', icon: svgIcon6, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '托兒服務', icon: svgIcon7, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '茶室', icon: svgIcon8, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '多功能室', icon: svgIcon9, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '商務便利設施', icon: svgIcon10, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '健身室', icon: svgIcon11, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '公共區域 Wi-Fi免費', icon: svgIcon12, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '貨幣兌換', icon: svgIcon13, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '行李寄存免費', icon: svgIcon14, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '叫醒服務', icon: svgIcon16, targetUrl: '/tabs/hotel_service_intro' },
|
||||
{ name: '關於酒店', icon: svgIcon16, targetUrl: '/tabs/hotel_intro' },
|
||||
];
|
||||
|
||||
interface MainTabsProps {}
|
||||
|
||||
const MainTabs: React.FC<MainTabsProps> = () => {
|
||||
let [buttonSvg, setButtonSvg] = useState<string | null>(null);
|
||||
|
||||
let [mainTabVisible, setMainTabVisible] = useState<'bottom' | undefined>(undefined);
|
||||
let [showCenterButton, setShowCenterButton] = useState(mainTabVisible == 'bottom');
|
||||
|
||||
const hideMainTab = () => {
|
||||
setMainTabVisible(undefined);
|
||||
setShowCenterButton(false);
|
||||
};
|
||||
const showMainTab = () => {
|
||||
setMainTabVisible('bottom');
|
||||
setShowCenterButton(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getButtonSvg().then((res) => setButtonSvg(res));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ServiceMenu buttonSvg={buttonSvg} hotelServiceMenu={hotelServiceMenu} showCenterButton={showCenterButton} />
|
||||
|
||||
{/* */}
|
||||
<IonTabs>
|
||||
<IonRouterOutlet>
|
||||
{/* REQ0117/default-route */}
|
||||
<Redirect exact path="/tabs" to="/tabs/events" />
|
||||
|
||||
{/*
|
||||
Using the render method prop cuts down the number of renders your components will have due to route changes.
|
||||
Use the component prop when your component depends on the RouterComponentProps passed in automatically.
|
||||
*/}
|
||||
|
||||
<Route path="/tabs/schedule" render={() => <SchedulePage />} exact={true} />
|
||||
<Route path="/tabs/speakers" render={() => <SpeakerList />} exact={true} />
|
||||
<Route path="/tabs/speakers/:id" component={SpeakerDetail} exact={true} />
|
||||
|
||||
<Route path="/tabs/schedule/:id" component={SessionDetail} />
|
||||
<Route path="/tabs/speakers/sessions/:id" component={SessionDetail} />
|
||||
<Route path="/tabs/map" render={() => <MapView />} exact={true} />
|
||||
|
||||
<Route path="/tabs/about" render={() => <About />} exact={true} />
|
||||
<Route path="/tabs/helloworld" render={() => <Helloworld />} exact={true} />
|
||||
|
||||
{/* */}
|
||||
<Route path={PATHS.CAROUSELL_ME} render={() => <CarousellMe />} exact={true} />
|
||||
<Route path={PATHS.CAROUSELL_ME_QR} component={QRPage} exact={true} />
|
||||
{/*
|
||||
<Route path="/tabs/carousell_me/insights" component={Insights} exact={true} />
|
||||
<Route path="/tabs/carousell_me/OffersMade" component={OffersMade} exact={true} />
|
||||
<Route path="/tabs/carousell_me/settings" component={Settings} exact={true} />
|
||||
<Route path="/tabs/carousell_me/my_profile" component={MyProfile} exact={true} />
|
||||
*/}
|
||||
|
||||
<TabAppRoute />
|
||||
</IonRouterOutlet>
|
||||
|
||||
<IonTabBar slot="bottom">
|
||||
{/*
|
||||
<IonTabButton tab="speakers" href={'/tabs/speakers'}>
|
||||
<IonIcon icon={calendar} />
|
||||
<IonLabel>Speakers</IonLabel>
|
||||
</IonTabButton>
|
||||
*/}
|
||||
|
||||
<IonTabButton tab="events" href={PATHS.EVENT_LIST}>
|
||||
<IonIcon icon={calendar} />
|
||||
<IonLabel>Event</IonLabel>
|
||||
</IonTabButton>
|
||||
<IonTabButton tab="nearby" href={PATHS.NEARBY_LIST}>
|
||||
<IonIcon icon={people} />
|
||||
<IonLabel>Nearby</IonLabel>
|
||||
</IonTabButton>
|
||||
{/*
|
||||
<IonTabButton tab="orders" href={PATHS.ORDERS_LIST}>
|
||||
<IonIcon icon={location} />
|
||||
<IonLabel>Order</IonLabel>
|
||||
</IonTabButton>
|
||||
*/}
|
||||
<IonTabButton disabled></IonTabButton>
|
||||
|
||||
<IonTabButton tab="message" href={PATHS.MESSAGE_LIST}>
|
||||
<IonIcon icon={informationCircle} />
|
||||
<IonLabel>Message</IonLabel>
|
||||
</IonTabButton>
|
||||
<IonTabButton tab="my_profile" href={PATHS.PROFILE}>
|
||||
<IonIcon icon={informationCircle} />
|
||||
<IonLabel>Profile</IonLabel>
|
||||
</IonTabButton>
|
||||
</IonTabBar>
|
||||
</IonTabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainTabs;
|
59
03_source/mobile/src/pages/MainTabs/style.scss
Normal file
@@ -0,0 +1,59 @@
|
||||
// TODO: Shadow Parts, https://ionicframework.com/docs/theming/css-shadow-parts
|
||||
ion-modal#main-tabs-modal {
|
||||
// --width: fit-content;
|
||||
--min-width: 250px;
|
||||
--height: fit-content;
|
||||
|
||||
--border-radius: 1rem 1rem 0 0;
|
||||
--box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
|
||||
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
// justify-content: flex-end;
|
||||
}
|
||||
|
||||
ion-modal#main-tabs-modal h1 {
|
||||
margin: 20px 20px 10px 20px;
|
||||
}
|
||||
|
||||
ion-modal#main-tabs-modal ion-icon {
|
||||
margin-right: 6px;
|
||||
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
|
||||
padding: 4px 0;
|
||||
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
ion-modal#main-tabs-modal .wrapper {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.colcenter {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
ion-item::part(native):hover {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.service-button {
|
||||
box-shadow: none;
|
||||
margin: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
ion-img {
|
||||
min-width: 80%;
|
||||
height: 40px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
}
|
210
03_source/mobile/src/pages/tabs/carousell_me/QRPage/index.tsx
Normal file
@@ -0,0 +1,210 @@
|
||||
import {
|
||||
IonBackButton,
|
||||
IonButton,
|
||||
IonButtons,
|
||||
IonContent,
|
||||
IonHeader,
|
||||
IonIcon,
|
||||
IonPage,
|
||||
IonPopover,
|
||||
IonSegment,
|
||||
IonSegmentButton,
|
||||
IonText,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
useIonRouter,
|
||||
useIonViewDidEnter,
|
||||
} from '@ionic/react';
|
||||
import { chevronBackOutline, star, starOutline } from 'ionicons/icons';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
// import AboutPopover from '../../components/AboutPopover';
|
||||
import { useIonAlert } from '@ionic/react';
|
||||
|
||||
import './style.scss';
|
||||
|
||||
import { AppContext } from '../../../../data/AppContext';
|
||||
import { createGesture, Gesture } from '@ionic/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import QRCode from 'react-qr-code';
|
||||
|
||||
interface QRCodeProps {}
|
||||
|
||||
type SessionListProps = {
|
||||
hide: boolean;
|
||||
};
|
||||
|
||||
const MyCode: React.FC<SessionListProps> = ({ hide }) => {
|
||||
if (hide) return <></>;
|
||||
return (
|
||||
<>
|
||||
<IonContent>
|
||||
<div style={{ background: 'white', padding: '16px', margin: '3rem' }}>
|
||||
<QRCode
|
||||
size={256}
|
||||
style={{ height: 'auto', maxWidth: '100%', width: '100%' }}
|
||||
value="http://louiscklaw.github.io"
|
||||
viewBox={`0 0 256 256`}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
margin: '3rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<IonText style={{ color: 'grey' }}>Scan to follow me on Carousell!</IonText>
|
||||
</div>
|
||||
</IonContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ScanCode: React.FC<SessionListProps> = ({ hide }) => {
|
||||
if (hide) return <></>;
|
||||
return (
|
||||
<>
|
||||
<IonContent>Scan code</IonContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const QRPage: React.FC<QRCodeProps> = () => {
|
||||
const [showPopover, setShowPopover] = useState(false);
|
||||
const [popoverEvent, setPopoverEvent] = useState<MouseEvent>();
|
||||
const [location, setLocation] = useState<'madison' | 'austin' | 'chicago' | 'seattle'>('madison');
|
||||
const [conferenceDate, setConferenceDate] = useState('2047-05-17T00:00:00-05:00');
|
||||
const [showAlert, hideAlert] = useIonAlert();
|
||||
|
||||
const { browser_store } = useContext(AppContext);
|
||||
|
||||
const refRectangle = useRef<HTMLDivElement>(null);
|
||||
const [swipeType, setSwipeType] = useState();
|
||||
const [deltaX, setDeltaX] = useState();
|
||||
const [velocityX, setVelocityX] = useState();
|
||||
const [swipeVerdict, setSwipeVerdict] = useState('helloworld');
|
||||
|
||||
const route = useIonRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (swipeVerdict == 'swipe-left')
|
||||
if (route.canGoBack() == true) {
|
||||
route.goBack();
|
||||
} else {
|
||||
route.push('/tabs/schedule');
|
||||
}
|
||||
}, [swipeVerdict]);
|
||||
|
||||
const onMove = (detail: any) => {
|
||||
const type = detail.type;
|
||||
const currentX = detail.currentX;
|
||||
const deltaX = detail.deltaX;
|
||||
const velocityX = detail.velocityX;
|
||||
setSwipeType(type);
|
||||
setDeltaX(deltaX);
|
||||
setVelocityX(velocityX);
|
||||
|
||||
if (type == 'pan')
|
||||
if (Math.abs(deltaX) > 50)
|
||||
if (velocityX > 0) {
|
||||
setSwipeVerdict('swipe-right');
|
||||
} else {
|
||||
setSwipeVerdict('swipe-left');
|
||||
}
|
||||
};
|
||||
|
||||
useIonViewDidEnter(() => {
|
||||
let gesture: any = {};
|
||||
if (refRectangle?.current) {
|
||||
gesture = createGesture({
|
||||
gestureName: 'helloworld',
|
||||
el: refRectangle.current,
|
||||
onMove: (detail) => {
|
||||
onMove(detail);
|
||||
},
|
||||
});
|
||||
|
||||
gesture.enable();
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (gesture) {
|
||||
// gesture?.destroy();
|
||||
}
|
||||
};
|
||||
}, [refRectangle]);
|
||||
|
||||
const handleStoreWrite = () => {
|
||||
(async () => {
|
||||
await browser_store.set('hello', 'world');
|
||||
})();
|
||||
};
|
||||
|
||||
const handleStoreRead = () => {
|
||||
(async () => {
|
||||
console.log(await browser_store.get('hello'));
|
||||
})();
|
||||
};
|
||||
|
||||
const handleStoreClear = () => {
|
||||
(async () => {
|
||||
await browser_store.clear();
|
||||
})();
|
||||
};
|
||||
|
||||
const handleStoreRemove = () => {
|
||||
(async () => {
|
||||
await browser_store.remove('hello');
|
||||
})();
|
||||
};
|
||||
|
||||
const handleStoreKeys = () => {
|
||||
(async () => {
|
||||
console.dir(await browser_store.keys());
|
||||
})();
|
||||
};
|
||||
|
||||
const handleStoreLength = () => {
|
||||
(async () => {
|
||||
console.dir(await browser_store.length());
|
||||
})();
|
||||
};
|
||||
|
||||
const userInput = 'javascript:alert("Oh no!")';
|
||||
const [segment, setSegment] = useState<'my_code' | 'scan_code'>('my_code');
|
||||
const { t } = useTranslation();
|
||||
|
||||
const router = useIonRouter();
|
||||
|
||||
return (
|
||||
<IonPage id="qr-page">
|
||||
<IonHeader translucent={true} className="ion-no-border">
|
||||
<IonToolbar>
|
||||
<IonButtons slot="start">
|
||||
<IonButton shape="round" onClick={() => router.goBack()}>
|
||||
<IonIcon icon={chevronBackOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
|
||||
<IonContent>
|
||||
<IonSegment
|
||||
mode={'md'}
|
||||
value={segment}
|
||||
onIonChange={(e) => setSegment(e.detail.value as any)}
|
||||
>
|
||||
<IonSegmentButton value="my_code">{t('My Code')}</IonSegmentButton>
|
||||
<IonSegmentButton value="scan_code">{t('Scan Code')}</IonSegmentButton>
|
||||
</IonSegment>
|
||||
|
||||
<MyCode hide={segment != 'my_code'} />
|
||||
<ScanCode hide={segment != 'scan_code'} />
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(QRPage);
|
@@ -0,0 +1,2 @@
|
||||
#qr-page {
|
||||
}
|
161
03_source/mobile/src/pages/tabs/carousell_me/settings/index.tsx
Normal file
@@ -0,0 +1,161 @@
|
||||
import {
|
||||
IonBackButton,
|
||||
IonButton,
|
||||
IonButtons,
|
||||
IonContent,
|
||||
IonHeader,
|
||||
IonIcon,
|
||||
IonItem,
|
||||
IonLabel,
|
||||
IonList,
|
||||
IonPage,
|
||||
IonPopover,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
useIonRouter,
|
||||
useIonViewDidEnter,
|
||||
} from '@ionic/react';
|
||||
import { chevronBackOutline, star, starOutline } from 'ionicons/icons';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
// import AboutPopover from '../../components/AboutPopover';
|
||||
import { useIonAlert } from '@ionic/react';
|
||||
|
||||
import './style.scss';
|
||||
|
||||
import {
|
||||
ImgCouponSvg,
|
||||
ImgDataSvg,
|
||||
ImgNotebookSvg,
|
||||
ImgPrinterSvg,
|
||||
ImgRiceSvg,
|
||||
ImgSuitcaseSvg,
|
||||
ImgTruckSvg,
|
||||
ImgVoiceSvg,
|
||||
} from './svgs';
|
||||
|
||||
interface SettingProps {}
|
||||
|
||||
const Settings: React.FC<SettingProps> = () => {
|
||||
const [showPopover, setShowPopover] = useState(false);
|
||||
const [popoverEvent, setPopoverEvent] = useState<MouseEvent>();
|
||||
const [location, setLocation] = useState<'madison' | 'austin' | 'chicago' | 'seattle'>('madison');
|
||||
const [conferenceDate, setConferenceDate] = useState('2047-05-17T00:00:00-05:00');
|
||||
const [showAlert, hideAlert] = useIonAlert();
|
||||
|
||||
// const { browser_store } = useContext(AppContext);
|
||||
|
||||
const refRectangle = useRef<HTMLDivElement>(null);
|
||||
const [swipeType, setSwipeType] = useState();
|
||||
const [deltaX, setDeltaX] = useState();
|
||||
const [velocityX, setVelocityX] = useState();
|
||||
const [swipeVerdict, setSwipeVerdict] = useState('helloworld');
|
||||
|
||||
const route = useIonRouter();
|
||||
|
||||
return (
|
||||
<IonPage id="settings-page">
|
||||
<IonHeader translucent={true} className="ion-no-border">
|
||||
<IonToolbar>
|
||||
<IonButtons slot="start">
|
||||
<IonButton onClick={() => route.goBack()}>
|
||||
<IonIcon slot="icon-only" icon={chevronBackOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</IonButtons>
|
||||
|
||||
<IonButtons slot="end">
|
||||
<IonButton onClick={() => {}}>
|
||||
{false ? (
|
||||
<IonIcon slot="icon-only" icon={star}></IonIcon>
|
||||
) : (
|
||||
<IonIcon slot="icon-only" icon={starOutline}></IonIcon>
|
||||
)}
|
||||
</IonButton>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent>
|
||||
<IonHeader collapse="condense">
|
||||
<IonToolbar>
|
||||
<IonTitle size="large">Settings</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
|
||||
<IonList>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgRiceSvg />
|
||||
<IonLabel>Edit Profile</IonLabel>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgPrinterSvg />
|
||||
<IonLabel>Quick and Auto reply</IonLabel>
|
||||
</IonItem>
|
||||
|
||||
{/* help and support */}
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<h3>Help & Support</h3>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgSuitcaseSvg />
|
||||
<IonLabel>Support Inbox</IonLabel>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgDataSvg />
|
||||
<IonLabel>Help Centen</IonLabel>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgTruckSvg />
|
||||
<IonLabel>Contact Us</IonLabel>
|
||||
</IonItem>
|
||||
|
||||
{/* Theme */}
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<h3>Theme</h3>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgPrinterSvg />
|
||||
<IonLabel>Dark Mode</IonLabel>
|
||||
</IonItem>
|
||||
|
||||
{/* Settings & Privacy */}
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<h3>Settings & Privacy</h3>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgVoiceSvg />
|
||||
<IonLabel>Change Password</IonLabel>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgVoiceSvg />
|
||||
<IonLabel>Notificatinos</IonLabel>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgDataSvg />
|
||||
<IonLabel>Auto-reserve items</IonLabel>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgPrinterSvg />
|
||||
<IonLabel>Save Photos</IonLabel>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgSuitcaseSvg />
|
||||
<IonLabel>Social Media</IonLabel>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgCouponSvg />
|
||||
<IonLabel>About Carousell</IonLabel>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgTruckSvg />
|
||||
<IonLabel>Logout</IonLabel>
|
||||
</IonItem>
|
||||
<IonItem lines="full" button routerLink="/tabs/carousell_me/my_profile">
|
||||
<ImgVoiceSvg />
|
||||
<IonLabel>Deactivate Account</IonLabel>
|
||||
</IonItem>
|
||||
</IonList>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Settings);
|
@@ -0,0 +1,2 @@
|
||||
#sample-blank-page {
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M908.056 171.944c-1.512 40.128-35.696 72.24-77.88 72.24-42.192 0-76.456-32.112-77.88-72.24H597.024c-1.512 40.128-35.64 72.24-77.88 72.24-42.192 0-76.344-32.112-77.784-72.24H284.584c-1.408 40.128-35.656 72.24-77.848 72.24-42.264 0-76.384-32.112-77.856-72.24H0v680.104h128.88c1.472-40.136 35.592-72.24 77.856-72.24 42.2 0 76.44 32.112 77.848 72.24h156.768c1.44-40.136 35.592-72.24 77.784-72.24 42.24 0 76.368 32.112 77.88 72.24h155.264c1.432-40.136 35.688-72.24 77.88-72.24 42.184 0 76.368 32.112 77.88 72.24H1024V171.944h-115.944z" fill="#F5B146" /><path d="M173.96 519.384h640.424v131.328H173.96z" fill="#E5226B" /><path d="M173.96 379.704h279.168v65.68H173.96z" fill="#0092D2" /><path d="M174.36 408.184h278.296v37.192H174.36z" fill="#0085BF" /><path d="M174.36 583.48h640.896v67.232H174.36z" fill="#C9005B" /></svg>
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M54.296 225.944h841.8v670.336H54.296z" fill="#F6AB20" /><path d="M812.904 225.944H54.296v670.328h330.472z" fill="#F5A517" /><path d="M984.52 940.952H76.544a31.472 31.472 0 0 1-31.488-31.488V123.288c0-17.4 14.08-31.488 31.488-31.488s31.488 14.08 31.488 31.488v754.696h876.496a31.472 31.472 0 0 1 31.48 31.488 31.472 31.472 0 0 1-31.488 31.48z" fill="#E6246B" /><path d="M260.632 692.352a22.896 22.896 0 0 1-14.872-40.304l116.176-111.912a22.704 22.704 0 0 1 21.256-4.584l193.424 56.232 154.808-241.2a22.896 22.896 0 1 1 38.568 24.728L605.92 630.936a22.888 22.888 0 0 1-25.664 9.616L382.272 582.96 275.504 686.848a22.768 22.768 0 0 1-14.872 5.504z" fill="#0093D3" /></svg>
|
After Width: | Height: | Size: 921 B |
@@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import CouponSvg from './coupon.svg';
|
||||
import DataSvg from './data.svg';
|
||||
import NotebookSvg from './notebook.svg';
|
||||
import PrinterSvg from './printer.svg';
|
||||
import RiceSvg from './rice.svg';
|
||||
import SuitcaseSvg from './suitcase.svg';
|
||||
import TruckSvg from './truck.svg';
|
||||
import VoiceSvg from './voice.svg';
|
||||
|
||||
const ImgSvg = ({ svg }: { svg: string }) => {
|
||||
return <img src={svg} width="40px" height="40px" style={{ paddingRight: '1rem' }} />;
|
||||
};
|
||||
|
||||
const ImgCouponSvg = () => <ImgSvg svg={CouponSvg} />;
|
||||
const ImgDataSvg = () => <ImgSvg svg={DataSvg} />;
|
||||
const ImgNotebookSvg = () => <ImgSvg svg={NotebookSvg} />;
|
||||
const ImgPrinterSvg = () => <ImgSvg svg={PrinterSvg} />;
|
||||
const ImgRiceSvg = () => <ImgSvg svg={RiceSvg} />;
|
||||
const ImgSuitcaseSvg = () => <ImgSvg svg={SuitcaseSvg} />;
|
||||
const ImgTruckSvg = () => <ImgSvg svg={TruckSvg} />;
|
||||
const ImgVoiceSvg = () => <ImgSvg svg={VoiceSvg} />;
|
||||
|
||||
export {
|
||||
ImgCouponSvg,
|
||||
ImgDataSvg,
|
||||
ImgNotebookSvg,
|
||||
ImgPrinterSvg,
|
||||
ImgRiceSvg,
|
||||
ImgSuitcaseSvg,
|
||||
ImgTruckSvg,
|
||||
ImgVoiceSvg,
|
||||
};
|
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M0 0.008h1024v1023.984H0z" fill="#F4F4F4" /><path d="M978.84 907.376a69.976 69.976 0 0 1-69.968 69.96h-789.52a69.976 69.976 0 0 1-69.968-69.96V210.408a69.984 69.984 0 0 1 69.968-69.968h789.52a69.984 69.984 0 0 1 69.968 69.968v696.968z" fill="#F4A417" /><path d="M49.384 270.616v636.76a69.976 69.976 0 0 0 69.968 69.96h458.392c76.84-184.088 280.688-706.72 280.688-706.72H49.384z" fill="#F4A417" /><path d="M49.384 305.304V210.408a69.984 69.984 0 0 1 69.968-69.968h789.52a69.984 69.984 0 0 1 69.968 69.968v94.896H49.384z" fill="#E37F19" /><path d="M362.12 281.64a60.208 60.208 0 0 1-60.208-60.2V60.216a60.216 60.216 0 0 1 120.416 0v161.216a60.216 60.216 0 0 1-60.208 60.208zM666.112 281.64a60.232 60.232 0 0 1-60.208-60.2V60.216A60.24 60.24 0 0 1 666.112 0.008c33.28 0 60.2 26.96 60.2 60.208v161.216a60.184 60.184 0 0 1-60.2 60.208z" fill="#E5226B" /><path d="M362.12 0.008a60.216 60.216 0 0 1 60.208 60.208v161.216a60.208 60.208 0 0 1-60.208 60.2M666.112 0.008c33.28 0 60.2 26.96 60.2 60.208v161.216a60.176 60.176 0 0 1-60.2 60.2" fill="#C8246D" /><path d="M782.52 480.928H221.864a30.08 30.08 0 0 1-30.104-30.104 30.08 30.08 0 0 1 30.104-30.104h560.664a30.08 30.08 0 0 1 30.104 30.104 30.096 30.096 0 0 1-30.112 30.104zM507.904 672.832H221.864c-16.64 0-30.104-13.464-30.104-30.104s13.464-30.112 30.104-30.112h286.04c16.64 0 30.104 13.472 30.104 30.112s-13.464 30.104-30.104 30.104z" fill="#D98D1B" /></svg>
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M254.832 410.496V84.984h514.336v325.512" fill="#0085BF" /><path d="M254.832 281.304v-196.32h514.336v196.32" fill="#0092D2" /><path d="M242.752 841.2H105.688C51.696 841.2 8 797.416 8 743.512V500.096c0-53.936 43.696-97.72 97.688-97.72h812.616c53.968 0 97.696 43.792 97.696 97.72v243.416c0 53.896-43.728 97.688-97.696 97.688H783.608" fill="#F5B146" /><path d="M8 532.256v211.256c0 53.896 43.696 97.688 97.688 97.688h812.616c53.968 0 97.696-43.792 97.696-97.688V532.256" fill="#EDA02F" /><path d="M254.832 718.288h514.328v219.368H254.832z" fill="#E5226B" /><path d="M254.832 862.832h514.328v76.192H254.832z" fill="#C9005B" /></svg>
|
After Width: | Height: | Size: 879 B |
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M991.608 398.368c0-80.704-65.44-146.144-146.144-146.144l-0.68 0.712c0-80.736-65.472-146.144-146.144-146.144l-2.44-2.92C665.816 52.112 596.352 16 515.552 16c-70.176 0-131.848 27.376-166.76 68.52a139.856 139.856 0 0 0-14.936 21.336l-1.272 0.944c-80.696 0-146.144 65.408-146.144 146.144l-0.024-0.72c-80.704 0-146.144 65.44-146.144 146.144" fill="#FFC033" /><path d="M991.608 398.368c0-57.088-65.44-103.336-146.144-103.336l-0.68 0.52c0-57.128-65.472-103.336-146.144-103.336l-2.44-2.08c-30.4-36.6-99.856-62.16-180.664-62.16-70.176 0-131.848 19.352-166.76 48.456-5.712 4.776-10.72 9.84-14.936 15.104l-1.272 0.68c-80.696 0-146.144 46.216-146.144 103.336L186.416 295.032c-80.704 0-146.144 46.248-146.144 103.336" fill="#FFA836" /><path d="M728.944 869.432V1008H299.88v-138.568" fill="#0092D2" /><path d="M1028.832 391.968c0 238.08-137.696 513.704-514.416 513.704-398.48 0-514.416-275.624-514.416-513.704h1028.832z" fill="#E5297F" /><path d="M510.128 905.48c1.496 0.032 2.792 0.192 4.288 0.192 376.72 0 514.416-275.624 514.416-513.704H510.128v513.512z" fill="#D3296E" /><path d="M798.84 391.968c0 238.08-76.128 513.704-284.424 513.704-220.32 0-284.424-275.624-284.424-513.704h568.848z" fill="#F73786" /><path d="M798.84 391.968H510.128v513.344c1.496 0.032 2.792 0.36 4.288 0.36 208.296 0 284.424-275.624 284.424-513.704z" fill="#E01E88" /></svg>
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M455.176 531.168V183.936h140.608v347.232h129.304v-387.2c0-49.248-40.056-89.344-89.296-89.344H415.176c-49.248 0-89.312 40.096-89.312 89.344v387.192h129.312z" fill="#E5226B" /><path d="M1016 876.376c0 50.888-41.224 92.112-92.056 92.112H100.12C49.224 968.488 8 927.264 8 876.376V374.424c0-50.888 41.224-92.12 92.12-92.12h823.832c50.832 0 92.056 41.232 92.056 92.12v501.952z" fill="#F5B146" /><path d="M342.064 968.488H100.12C49.224 968.488 8 927.264 8 876.376V374.424c0-50.888 41.224-92.12 92.12-92.12h791.504l-549.56 686.184z" fill="#FFC83E" /><path d="M762.824 283.216h64.648v686.16h-64.648zM201.96 283.216h64.656v686.16h-64.656z" fill="#0092D2" /><path d="M234.288 283.216h32.328v686.16h-32.328zM795.144 283.216h32.328v686.16h-32.328z" fill="#0085BF" /></svg>
|
After Width: | Height: | Size: 1011 B |
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M425.176 123.4h554.432v424.992H425.176z" fill="#E6246B" /><path d="M893.832 809.152c47.384 0 85.784-38.392 85.784-85.784V543.624H425.976V241.288l-234.064-0.768L40.92 492.192V723.36c0 47.392 38.392 85.784 85.752 85.784h767.16z" fill="#F6B246" /><path d="M893.832 809.152c47.384 0 85.784-38.392 85.784-85.784V603.832H40.92V723.36c0 47.392 38.392 85.784 85.752 85.784h767.16z" fill="#ECD4BE" /><path d="M853.728 824.552c0 56.152-45.504 101.592-101.6 101.592-56.152 0-101.592-45.448-101.592-101.592 0-56.096 45.448-101.6 101.592-101.6 56.088 0 101.6 45.512 101.6 101.6zM379.584 824.552c0 56.152-45.48 101.592-101.6 101.592s-101.6-45.448-101.6-101.592c0-56.096 45.48-101.6 101.6-101.6s101.6 45.512 101.6 101.6z" fill="#0093D3" /><path d="M264.192 454.568H62.848l109.128-178.736h92.216z" fill="#E09431" /></svg>
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M261.84 693.464V286.064c0-131.496 106.592-238.128 238.12-238.128 131.552 0 238.16 106.632 238.16 238.128l0.76 407.392S619.496 786.472 500.32 784.696c-125.416-1.84-238.48-91.232-238.48-91.232z" fill="#F0AF2D" /><path d="M261.84 694.048c-119.032 0-215.368-78.816-215.368-206.896 0-134.936 96.336-206.96 215.368-206.96v413.856z" fill="#0092D2" /><path d="M738.872 693.464l-0.76-407.392c0-3.616-0.384-7.112-0.536-10.696L261.84 648.512v44.944s113.064 89.4 238.472 91.24c119.184 1.784 238.56-91.232 238.56-91.232z" fill="#EEA03A" /><path d="M955.944 485.616c0-143.696-97.128-208.576-217.072-208.576v397.448l-92.456 218.248a30.128 30.128 0 0 0 27.72 41.84c11.696 0 22.864-6.88 27.728-18.376l97.04-229.04c90.664-21.392 157.04-92.304 157.04-201.544z" fill="#1A8DCC" /><path d="M549.224 1001.096a60.272 60.272 0 0 1-56.44-39.232 60.24 60.24 0 0 1 35.456-77.432l107.976-40.168c31.168-11.52 65.832 4.296 77.44 35.464a60.264 60.264 0 0 1-35.456 77.432l-107.976 40.16a60.832 60.832 0 0 1-21 3.776z" fill="#E5226B" /></svg>
|
After Width: | Height: | Size: 1.2 KiB |