This commit is contained in:
louiscklaw
2025-06-06 11:50:25 +08:00
parent d453144500
commit 3217a8d594
22 changed files with 501 additions and 494 deletions

View File

@@ -6,8 +6,8 @@ import { Route, Redirect } from 'react-router';
// import Tab1 from './AppPages/Tab1';
// import Tab2 from './AppPages/Tab2';
import Topic from './pages/Topic.jsx';
import Home from './pages/Home.jsx';
import Topic from './pages/Topic';
import Home from './pages/Home';
import './style.scss';
@@ -15,12 +15,14 @@ function DemoAccordionTutorial() {
return (
<IonTabs className="demo-accordion-tutorial">
<IonRouterOutlet>
{/* <Route exact path="/demo-accordion-tutorial/tab1">
{/*
<Route exact path="/demo-accordion-tutorial/tab1">
<Tab1 />
</Route>
<Route exact path="/demo-accordion-tutorial/tab2">
<Tab2 />
</Route> */}
</Route>
*/}
<Route exact path="/demo-accordion-tutorial/home">
<Home />
@@ -30,7 +32,9 @@ function DemoAccordionTutorial() {
<Topic />
</Route>
<Redirect exact path="/demo-accordion-tutorial" to="/demo-accordion-tutorial/tab1" />
<Redirect exact path="/demo-accordion-tutorial" to="/demo-accordion-tutorial/home" />
{/* <Redirect exact path="/demo-accordion-tutorial" to="/demo-accordion-tutorial/tab1" /> */}
</IonRouterOutlet>
{/*

View File

@@ -51,11 +51,13 @@ import {
book,
car,
cart,
cashOutline,
chatbubbleEllipses,
chatbubbleOutline,
chevronBackOutline,
chevronForward,
chevronForwardOutline,
colorPaletteOutline,
createOutline,
document,
documentTextOutline,
@@ -63,9 +65,12 @@ import {
giftOutline,
globeSharp,
heart,
keyOutline,
languageOutline,
layers,
list,
listCircle,
mapOutline,
menuOutline,
people,
person,
@@ -202,6 +207,313 @@ const SettingsPage: React.FC<SettingsProps> = ({ speakers, speakerSessions, logo
{/* */}
{/* */}
{/* */}
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_ACCORDION_TUTORIAL, 'forward')}>
<IonIcon slot="start" icon={list} size="large"></IonIcon>
<IonLabel>Demo Accordion Tutorial</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_BANKING_UI, 'forward')}>
<IonIcon slot="start" icon={cashOutline} size="large"></IonIcon>
<IonLabel>
Demo Banking UI <span style={{ fontWeight: 'bold' }}>(in the middle, style outstanding)</span>
</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_CAPACITOR_GOOGLE_MAPS_TUTORIAL, 'forward')}>
<IonIcon slot="start" icon={mapOutline} size="large"></IonIcon>
<IonLabel>
Demo Capacitor Google Maps Tutorial <span style={{ fontWeight: 'bold' }}>need a google map api key</span>
</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_COLOR_TUTORIAL, 'forward')}>
<IonIcon slot="start" icon={colorPaletteOutline} size="large"></IonIcon>
<IonLabel>Demo Color Tutorial</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
{/*
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_ECOMMERCE_EXAMPLE, 'forward')}>
<IonIcon slot="start" icon={cartOutline} size="large"></IonIcon>
<IonLabel>Demo Ecommerce Example</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_FACEBOOK_CLONE, 'forward')}>
<IonIcon slot="start" icon={logoFacebook} size="large"></IonIcon>
<IonLabel>Demo Facebook Clone</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_FAST_FOOD_APP, 'forward')}>
<IonIcon slot="start" icon={restaurantOutline} size="large"></IonIcon>
<IonLabel>Demo Fast Food App</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_FLOATING_TABS, 'forward')}>
<IonIcon slot="start" icon={layersOutline} size="large"></IonIcon>
<IonLabel>Demo Floating Tabs</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_INSTAGRAM_CLONE, 'forward')}>
<IonIcon slot="start" icon={imageOutline} size="large"></IonIcon>
<IonLabel>Demo Instagram Clone</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_KANBAN_BOARD, 'forward')}>
<IonIcon slot="start" icon={gridOutline} size="large"></IonIcon>
<IonLabel>Demo Kanban Board</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_ORDERING_APP, 'forward')}>
<IonIcon slot="start" icon={pizzaOutline} size="large"></IonIcon>
<IonLabel>Demo Ordering App</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_PROFILE_EXAMPLE, 'forward')}>
<IonIcon slot="start" icon={personOutline} size="large"></IonIcon>
<IonLabel>Demo Profile Example</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_PULLSTATE_TUTORIAL, 'forward')}>
<IonIcon slot="start" icon={codeWorkingOutline} size="large"></IonIcon>
<IonLabel>Demo Pullstate Tutorial</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_ADD_TO_CART, 'forward')}>
<IonIcon slot="start" icon={cartOutline} size="large"></IonIcon>
<IonLabel>Demo React Add to Cart</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_CALCULATOR, 'forward')}>
<IonIcon slot="start" icon={calculatorOutline} size="large"></IonIcon>
<IonLabel>Demo React Calculator</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_DRAWING_CANVAS, 'forward')}>
<IonIcon slot="start" icon={brushOutline} size="large"></IonIcon>
<IonLabel>Demo React Drawing Canvas</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_HOOK_FORM_EXAMPLE, 'forward')}>
<IonIcon slot="start" icon={codeSlashOutline} size="large"></IonIcon>
<IonLabel>Demo React Hook Form Example</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_ITEM_LIST, 'forward')}>
<IonIcon slot="start" icon={listOutline} size="large"></IonIcon>
<IonLabel>Demo React Item List</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_LIFECYCLES, 'forward')}>
<IonIcon slot="start" icon={refreshOutline} size="large"></IonIcon>
<IonLabel>Demo React Lifecycles</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_LOGIN, 'forward')}>
<IonIcon slot="start" icon={logInOutline} size="large"></IonIcon>
<IonLabel>Demo React Login</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_MARVEL_APP, 'forward')}>
<IonIcon slot="start" icon={flashOutline} size="large"></IonIcon>
<IonLabel>Demo React Marvel App</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_MOVIE_APP_WITH_ALGOLIA, 'forward')}>
<IonIcon slot="start" icon={filmOutline} size="large"></IonIcon>
<IonLabel>Demo React Movie App with Algolia</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_NOTES, 'forward')}>
<IonIcon slot="start" icon={documentTextOutline} size="large"></IonIcon>
<IonLabel>Demo React Notes</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_ONBOARDING_UI, 'forward')}>
<IonIcon slot="start" icon={walkOutline} size="large"></IonIcon>
<IonLabel>Demo React Onboarding UI</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_REACT_PROFILE_DASHBOARD_UI, 'forward')):
<IonIcon slot="start" icon={personCircleOutline} size="large"></IonIcon>
<IonLabel>Demo React Profile Dashboard UI</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_QR_CODE, 'forward')}>
<IonIcon slot="start" icon={qrCodeOutline} size="large"></IonIcon>
<IonLabel>Demo React QR Code</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_REACT_QUOTES, 'forward')):
<IonIcon slot="start" icon={bookOutline} size="large"></IonIcon>
<IonLabel>Demo React Quotes</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_REACT_SHOP_UI, 'forward')):
<IonIcon slot="start" icon={cartOutline} size="large"></IonIcon>
<IonLabel>Demo React Shop UI</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_REACT_TABS_MENUS_CUSTOM, 'forward')):
<IonIcon slot="start" icon={layersOutline} size="large"></IonIcon>
<IonLabel>Demo React Tabs Menus Custom</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_REACT_THEME_SWITCHER, 'forward')):
<IonIcon slot="start" icon={colorPaletteOutline} size="large"></IonIcon>
<IonLabel>Demo React Theme Switcher</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_REACT_WHATSAPP_CLONE, 'forward')):
<IonIcon slot="start" icon={chatbubbleEllipsesOutline} size="large"></IonIcon>
<IonLabel>Demo React WhatsApp Clone</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_SKELETON_TEXT, 'forward')):
<IonIcon slot="start" icon={codeWorkingOutline} size="large"></IonIcon>
<IonLabel>Demo Skeleton Text</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_STICKY_BOTTOM_SHEET_EXAMPLE, 'forward')):
<IonIcon slot="start" icon={paperPlaneOutline} size="large"></IonIcon>
<IonLabel>Demo Sticky Bottom Sheet Example</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_STORAGE_EXAMPLE, 'forward')):
<IonIcon slot="start" icon={cloudOutline} size="large"></IonIcon>
<IonLabel>Demo Storage Example</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_SWIPERJS_TUTORIAL, 'forward')):
<IonIcon slot="start" icon={imagesOutline} size="large"></IonIcon>
<IonLabel>Demo SwiperJS Tutorial</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
<IonList inset={false}>
<IonItem button={true} onClick(() => router.push(paths.DEMO_WEATHER_APP_UI, 'forward')):
<IonIcon slot="start" icon={sunnyOutline} size="large"></IonIcon>
<IonLabel>Demo Weather App UI</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
*/}
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_2FA_EXAMPLE, 'forward')}>
<IonIcon slot="start" icon={keyOutline} size="large"></IonIcon>
<IonLabel>Demo 2FA Example</IonLabel>
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
{/*
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_WHATSAPP_CLONE, 'forward')}>
<IonIcon slot="start" icon={chatbubbleEllipses} size="large"></IonIcon>
@@ -211,6 +523,7 @@ const SettingsPage: React.FC<SettingsProps> = ({ speakers, speakerSessions, logo
<IonIcon icon={chevronForwardOutline}></IonIcon>
</IonItem>
</IonList>
*/}
<IonList inset={false}>
<IonItem button={true} onClick={() => router.push(paths.DEMO_REACT_POLL_APP, 'forward')}>

View File

@@ -16,7 +16,7 @@ import {
import { heartOutline } from 'ionicons/icons';
import { useStoreState } from 'pullstate';
import { useState } from 'react';
import { ProductModal } from '../components/ProductModal';
import { ProductModal } from '../TestComponents/ProductModal';
import { FavouritesStore } from '../store';
import { getFavourites } from '../store/Selectors';

View File

@@ -23,8 +23,8 @@ import { chevronBack, filter } from 'ionicons/icons';
import { useRef } from 'react';
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
import { FilterModal } from '../components/FilterModal';
import { ProductModal } from '../components/ProductModal';
import { FilterModal } from '../TestComponents/FilterModal';
import { ProductModal } from '../TestComponents/ProductModal';
import { capitalize, productInfo } from '../utils';
const ProductType = () => {

View File

@@ -13,8 +13,8 @@ import Place from '../pages/Place';
// If using ionicons, import here and pass as ref to tabRoutes
// Import custom tab menu
import Tabs from '../components/Tabs';
import SubPages from '../components/SubPages';
import Tabs from '../TestComponents/Tabs';
import SubPages from '../TestComponents/SubPages';
// Array of objects representing tab pages
// These will be the main tabs across the app

View File

@@ -1,16 +1,4 @@
import {
IonButton,
IonButtons,
IonCol,
IonContent,
IonHeader,
IonIcon,
IonPage,
IonRow,
IonTitle,
IonToolbar,
useIonRouter,
} from '@ionic/react';
import { IonButton, IonButtons, IonCol, IonContent, IonHeader, IonIcon, IonPage, IonRow, IonTitle, IonToolbar, useIonRouter } from '@ionic/react';
import { Geolocation } from '@capacitor/geolocation';
import { useEffect, useState } from 'react';
@@ -35,9 +23,7 @@ function Tab1() {
const getAddress = async (coords) => {
const query = `${coords.latitude},${coords.longitude}`;
const response = await fetch(
`https://api.weatherapi.com/v1/current.json?key=f93eb660b2424258bf5155016210712&q=${query}`
);
const response = await fetch(`https://api.weatherapi.com/v1/current.json?key=f93eb660b2424258bf5155016210712&q=${query}`);
const data = await response.json();
console.log(data);
@@ -81,13 +67,7 @@ function Tab1() {
</IonCol>
</IonRow>
<div style={{ marginTop: '-1.5rem' }}>
{currentWeather ? (
<CurrentWeather currentWeather={currentWeather} />
) : (
<SkeletonDashboard />
)}
</div>
<div style={{ marginTop: '-1.5rem' }}>{currentWeather ? <CurrentWeather currentWeather={currentWeather} /> : <SkeletonDashboard />}</div>
</IonContent>
</IonPage>
);

View File

@@ -1,58 +0,0 @@
import { CreateAnimation, IonButton, IonIcon } from "@ionic/react";
import { cartOutline } from "ionicons/icons";
import { useRef, useState } from "react";
import { addToCart } from "../store/CartStore";
export const AddToCartButton = ({product}) => {
const animationRef = useRef();
const [hidden, setHidden] = useState(true);
const floatStyle = {
display: hidden ? "none" : "",
position: "absolute"
};
const floatGrowAnimation = {
property: "transform",
fromValue: "translateY(0) scale(1)",
toValue: "translateY(-55px) scale(1.5)"
};
const colorAnimation = {
property: "color",
fromValue: "green",
toValue: "green"
};
const mainAnimation = {
duration: 1500,
iterations: "1",
fromTo: [ floatGrowAnimation, colorAnimation ],
easing: "cubic-bezier(0.25, 0.7, 0.25, 0.7)"
};
const handleAddToCart = async product => {
setHidden(false);
await animationRef.current.animation.play();
setHidden(true);
addToCart(product);
}
return (
<IonButton color="dark" expand="full" onClick={() => handleAddToCart(product)}>
<IonIcon icon={cartOutline} />&nbsp;
Add to Cart
<CreateAnimation ref={animationRef} {...mainAnimation}>
<IonIcon icon={cartOutline} size="large" style={floatStyle} />
</CreateAnimation>
</IonButton>
);
}

View File

@@ -1,23 +0,0 @@
import { IonBreadcrumb, IonBreadcrumbs, IonIcon } from "@ionic/react";
import { fastFoodOutline } from "ionicons/icons";
import { useState } from "react";
export const Breadcrumbs = () => {
const [maxItems, setMaxItems] = useState(2);
const handleClick = () => {
setMaxItems(undefined);
}
return (
<IonBreadcrumbs maxItems={maxItems} onIonCollapsedClick={handleClick}>
<IonBreadcrumb color="medium">Page 1</IonBreadcrumb>
<IonBreadcrumb color="medium">Page 2</IonBreadcrumb>
<IonBreadcrumb color="medium">Page 3</IonBreadcrumb>
<IonBreadcrumb>Page 4</IonBreadcrumb>
</IonBreadcrumbs>
);
}

View File

@@ -1,82 +0,0 @@
import { useStoreState } from "pullstate";
import { useEffect, useState } from "react";
import { CartStore } from "../store";
import { addToCart } from "../store/CartStore";
import { getCart } from "../store/Selectors";
const { IonPage, IonHeader, IonToolbar, IonTitle, IonButtons, IonIcon, IonContent, IonGrid, IonRow, IonItem, IonLabel, IonText, IonThumbnail, IonFooter, IonCol, IonButton, IonItemSliding, IonItemOptions, IonItemOption } = require("@ionic/react");
const { close } = require("ionicons/icons");
export const CartModal = props => {
const cart = useStoreState(CartStore, getCart);
const [totalPrice, setTotalPrice] = useState(0);
useEffect(() => {
let total = 0;
cart.forEach(item => total += parseInt(item.price.replace("£", "")));
setTotalPrice(total);
}, [cart]);
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Cart</IonTitle>
<IonButtons slot="end" onClick={props.close}>
<IonIcon icon={close} size="large" />
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent>
<IonGrid>
<IonRow style={{borderBottom: "1px solid black"}} className="ion-margin-bottom">
<IonItem lines="none">
<IonLabel>
<h1>{cart.length} products in your cart</h1>
<IonText color="medium">
<h2>Review products and checkout</h2>
</IonText>
</IonLabel>
</IonItem>
</IonRow>
</IonGrid>
{cart.map((item, index) => (
<IonItemSliding>
<IonItem key={index} lines="none" className="ion-padding-end" style={{paddingTop: "0.75rem", paddingBottom: "0.75rem"}}>
<IonThumbnail>
<img src={item.image} alt="item" />
</IonThumbnail>
<IonLabel className="ion-padding-start ion-text-wrap">
<h2>{item.title}</h2>
<p>{item.price}</p>
</IonLabel>
</IonItem>
<IonItemOptions side="end">
<IonItemOption color="danger" onClick={() => addToCart(item)}>
Remove
</IonItemOption>
</IonItemOptions>
</IonItemSliding>
))}
</IonContent>
<IonFooter className="ion-padding-bottom ion-padding-start ion-padding-end" style={{paddingBottom: "3rem"}}>
<IonRow className="ion-justify-content-between">
<IonCol size="8">
<h1>Total</h1>
</IonCol>
<IonCol size="4">
<h1>£{totalPrice.toFixed(2)}</h1>
</IonCol>
</IonRow>
<IonButton expand="block" color="dark">Checkout &rarr;</IonButton>
</IonFooter>
</IonPage>
);
}

View File

@@ -1,36 +0,0 @@
import { IonButton, IonCol, IonContent, IonGrid, IonHeader, IonRow, IonTitle, IonToolbar } from "@ionic/react";
export const FilterModal = ({productsRef, filterCriteria, setFilterCriteria, dismiss, filters}) => {
const filterProducts = async filter => {
await productsRef.current.classList.add("animate__fadeOutLeft");
setTimeout(() => {
productsRef.current.classList.remove("animate__fadeOutLeft");
productsRef.current.classList.add("animate__fadeInRight");
setFilterCriteria(filter);
}, 500);
dismiss();
}
return (
<IonContent>
<IonHeader>
<IonToolbar color="none" style={{"--border-style": "none"}}>
<IonTitle className="ion-margin-top">Filter</IonTitle>
</IonToolbar>
</IonHeader>
<IonGrid>
<IonRow>
{filters.map(f => (
<IonCol key={f} size="3">
<IonButton expand="full" color={filterCriteria === f ? "dark" : "light"} onClick={() => filterProducts(f)}>{f}</IonButton>
</IonCol>
))}
</IonRow>
</IonGrid>
</IonContent>
);
}

View File

@@ -1,88 +0,0 @@
ion-card {
margin: 0;
/* margin-top: var(--ion-safe-area-top); */
z-index: -1;
border-radius: 0px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
box-shadow: none;
aspect-ratio: 1 / 1;
}
@supports not (aspect-ratio: 1 / 1) {
ion-card::before {
float: left;
padding-top: 100%;
content: '';
}
ion-card::after {
display: block;
content: '';
clear: both;
}
}
ion-card-header {
position: absolute;
bottom: 0;
width: 100%;
/* background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.7) 100%); */
background: rgba(0, 0, 0, 0.5)
}
ion-card-title,
ion-card-subtitle {
color: white;
}
ion-card-header ion-card-title {
margin: 0 0 6px 0;
font-size: 22px;
}
ion-card-header ion-card-subtitle {
text-transform: none;
font-weight: 500;
font-size: 16px;
}
ion-card-content {
height: calc(60px + var(--ion-safe-area-top));
background: linear-gradient(0deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.5) 100%);
}
#close-button {
position: fixed;
top: max(var(--ion-safe-area-top), 16px);
right: 8px;
}
#fave-button {
position: fixed;
top: max(var(--ion-safe-area-top), 16px);
left: 8px;
}
#product-view-buttons {
z-index: 10;
background: linear-gradient(360deg, rgba(0, 0, 0, 0) 0%, rgba(82, 82, 82, 0.9) 100%) !important;
position: absolute;
width: 100%;
height: 4rem;
}
.sticky-bottom {
position: fixed;
bottom: 0;
}

View File

@@ -1,76 +0,0 @@
import { IonButton, IonButtons, IonCard, IonCardHeader, IonCardSubtitle, IonCardTitle, IonCol, IonContent, IonFooter, IonIcon, IonLabel, IonNote, IonRow, IonText, IonToolbar } from "@ionic/react";
import { closeCircle, heart, heartOutline } from "ionicons/icons";
import { useStoreState } from "pullstate";
import { useRef } from "react";
import { checkFavourites } from "../store/Selectors";
import { addToFavourites } from "../store/FavouritesStore";
import { FavouritesStore } from "../store";
import "./ProductModal.css";
import { ProductReviews } from "./ProductReviews";
import { ProductSpecificationsAccordion } from "./ProductSpecificationsAccordion";
import { AddToCartButton } from "./AddToCartButton";
export const ProductModal = props => {
const { dismiss, category = false, product } = props;
const isFavourite = useStoreState(FavouritesStore, checkFavourites(product));
const contentRef = useRef(null);
return (
<>
<IonContent ref={contentRef}>
<IonButtons id="product-view-buttons">
<IonButton color="light" onClick={dismiss} id="close-button">
<IonIcon icon={closeCircle} size="large" />
</IonButton>
<IonButton color="danger" onClick={() => addToFavourites(product, category)} id="fave-button">
<IonIcon icon={isFavourite ? heart : heartOutline} size="large" />
</IonButton>
</IonButtons>
<IonCard style={{backgroundImage: `url('${product.image}')`}}>
<IonCardHeader>
<IonCardTitle>{product.title}</IonCardTitle>
<IonCardSubtitle>{product.price}</IonCardSubtitle>
</IonCardHeader>
</IonCard>
<div className="ion-padding">
<IonRow className="ion-align-items-center">
<IonCol>
<IonText size="large" className="page-title">
<IonNote>shop</IonNote>
<IonLabel>{category ? category : "Favourite"}</IonLabel>
</IonText>
</IonCol>
<ProductReviews reviews={product.reviews} />
</IonRow>
<h2>Product Description</h2>
<IonText>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam elit felis, molestie id venenatis at, commodo ac tortor. Pellentesque tempus aliquet purus, sed vulputate elit tempus ut.</IonText>
<h2>Product Specifications</h2>
<ProductSpecificationsAccordion contentRef={contentRef} type={category} />
</div>
</IonContent>
<IonFooter collapse="fade">
<IonToolbar>
<IonRow className="ion-justify-content-between ion-align-items-center">
<IonCol size="3">
<IonButton expand="full" color="light">{product.price}</IonButton>
</IonCol>
<IonCol size="8" className="ion-text-right">
<AddToCartButton product={product} />
</IonCol>
</IonRow>
</IonToolbar>
</IonFooter>
</>
);
}

View File

@@ -1,23 +0,0 @@
import { IonCol, IonIcon, IonNote } from "@ionic/react";
import { star } from "ionicons/icons";
import { useEffect, useState } from "react";
import { randomCount } from "../utils";
export const ProductReviews = () => {
// This count could come from the product (if real data was fed)
const [reviewCount, setReviewCount] = useState(0);
useEffect(() => {
setReviewCount(randomCount());
}, []);
return (
<IonCol className="ion-text-right">
<IonIcon color="warning" icon={star} />
&nbsp;&nbsp;
<IonNote>{reviewCount} review{reviewCount > 1 && "s"}</IonNote>
</IonCol>
);
}

View File

@@ -1,58 +0,0 @@
import { IonAccordion, IonAccordionGroup, IonItem, IonLabel, IonList, IonNote } from "@ionic/react";
import { useRef } from "react";
import { productSpecs } from "../utils";
export const ProductSpecificationsAccordion = ({type, contentRef}) => {
const accordionGroupRef = useRef(null);
const log = () => {
const selectedAccordion = accordionGroupRef.current.value;
if (selectedAccordion) {
setTimeout(() => contentRef.current.scrollToBottom(400), 200);
}
}
return (
<IonAccordionGroup ref={accordionGroupRef} onIonChange={log}>
{Object.keys(productSpecs).map((spec, index) => {
const {header, options, wrapText = false, noteColor = false} = productSpecs[spec];
return (
<IonAccordion key={`accordion_${header}_${index}`}>
<IonItem slot="header" className="ion-no-padding">
<IonLabel>{header}</IonLabel>
</IonItem>
<IonList slot="content" className="ion-no-padding">
{options.map((option, index2) => {
const {label, value} = option;
return (
<IonItem key={`accordion_${header}_${option}_${index2}`} className="ion-no-padding">
<IonLabel>
<h3>{label}</h3>
</IonLabel>
<IonLabel className={wrapText && "ion-text-wrap"}>
<IonNote color={noteColor ? (value ? "success" : "danger") : "medium"}>
{noteColor ? (value ? "In stock" : "Out of stock") : value}
</IonNote>
</IonLabel>
</IonItem>
);
})}
</IonList>
</IonAccordion>
);
})}
</IonAccordionGroup>
);
}