Skip to content

Commit 2ab47f8

Browse files
committed
add admin switching, item display logic, polish UI
1 parent aac6800 commit 2ab47f8

19 files changed

+1031
-279
lines changed

examples/ecommerce-jewellery-store/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
1111
rel="stylesheet">
1212
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
13-
<title>Vite + React + TS</title>
13+
<title>Ecommerce Jewellery Store</title>
1414

1515
</head>
1616

examples/ecommerce-jewellery-store/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,23 @@
1111
},
1212
"dependencies": {
1313
"@progress/kendo-data-query": "^1.7.0",
14-
"@progress/kendo-drawing": "^1.21.0",
14+
"@progress/kendo-drawing": "^1.21.1",
1515
"@progress/kendo-licensing": "^1.3.5",
16+
"@progress/kendo-react-animation": "^8.5.0",
1617
"@progress/kendo-react-buttons": "^8.5.0",
1718
"@progress/kendo-react-common": "^8.5.0",
19+
"@progress/kendo-react-data-tools": "^8.5.0",
1820
"@progress/kendo-react-dateinputs": "^8.5.0",
1921
"@progress/kendo-react-dropdowns": "^8.5.0",
2022
"@progress/kendo-react-form": "^8.5.0",
23+
"@progress/kendo-react-grid": "^8.5.0",
2124
"@progress/kendo-react-indicators": "^8.5.0",
2225
"@progress/kendo-react-inputs": "^8.5.0",
2326
"@progress/kendo-react-intl": "^8.5.0",
2427
"@progress/kendo-react-layout": "^8.5.0",
28+
"@progress/kendo-react-chart-wizard": "^8.5.0",
2529
"@progress/kendo-react-notification": "^8.5.0",
30+
"@progress/kendo-react-popup": "^8.5.0",
2631
"@progress/kendo-react-progressbars": "^8.5.0",
2732
"@progress/kendo-react-treeview": "^8.5.0",
2833
"@progress/kendo-svg-icons": "^3.3.0",
Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import React from "react";
12
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
23
import Header from "./components/Header";
34
import Footer from "./components/Footer";
@@ -12,29 +13,36 @@ import { SizedParent } from "./components/SizedParent";
1213
import { DetailedCategory } from "./pages/DetailedCategory";
1314
import { ProductDetails } from "./pages/ProductsDetails";
1415
import { CartProvider } from "./helpers/CartContext";
15-
import { ShoppingCartList } from "./components/ShoppingCartList";
16+
import { AdminProvider } from './helpers/AdminContext';
17+
import { CategoriesProvider } from './helpers/CategoriesContext';
18+
import { ShoppingCartList } from "./components/ShoppingCartList"; // Adjust path if necessary
1619

1720
function App() {
1821
return (
1922
<CartProvider>
20-
<Router>
21-
<Header />
22-
<SizedParent>
23-
<Routes>
24-
<Route path="/" element={<Home />} />
25-
<Route path="/paymentdetails" element={<PaymentDetails />} />
26-
<Route path="/thankyou" element={<ThankYou />} />
27-
<Route path="/contacts" element={<Contacts />} />
28-
<Route path="/products" element={<AllProductsListView />} />
29-
<Route path="/category" element={<DetailedCategory />} />
30-
<Route path="/product/:id" element={<ProductDetails />} />
31-
<Route path="/shoppingcart" element={<ShoppingCartList />} />
32-
</Routes>
33-
</SizedParent>
34-
<Footer />
35-
</Router>
23+
<AdminProvider>
24+
<CategoriesProvider>
25+
<Router>
26+
<Header />
27+
<SizedParent>
28+
<Routes>
29+
<Route path="/" element={<Home />} />
30+
<Route path="/paymentdetails" element={<PaymentDetails />} />
31+
<Route path="/thankyou" element={<ThankYou />} />
32+
<Route path="/contacts" element={<Contacts />} />
33+
<Route path="/products" element={<AllProductsListView />} />
34+
<Route path="/category" element={<DetailedCategory />} />
35+
<Route path="/product/:id" element={<ProductDetails />} />
36+
<Route path="/shoppingcart" element={<ShoppingCartList />} />
37+
<Route path="/contacts" element={<Contacts />} />
38+
</Routes>
39+
</SizedParent>
40+
<Footer />
41+
</Router>
42+
</CategoriesProvider>
43+
</AdminProvider>
3644
</CartProvider>
3745
);
3846
}
3947

40-
export default App;
48+
export default App;
559 KB
Loading
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
import * as React from 'react';
2+
import { getter } from '@progress/kendo-react-common';
3+
import {
4+
Grid,
5+
GridColumn,
6+
GridSelectionChangeEvent,
7+
GridHandle,
8+
getSelectedState,
9+
GridKeyDownEvent,
10+
getSelectedStateFromKeyDown,
11+
GridSortChangeEvent,
12+
} from '@progress/kendo-react-grid';
13+
import {
14+
ChartWizard,
15+
getWizardDataFromGridSelection,
16+
} from '@progress/kendo-react-chart-wizard';
17+
import { Button } from '@progress/kendo-react-buttons';
18+
import { orderBy, groupBy } from '@progress/kendo-data-query';
19+
import { chartAreaStackedIcon } from '@progress/kendo-svg-icons';
20+
import { sampleData, SampleDataItem } from '../data/shared-gd-sampleChartData';
21+
import { Pager, PageChangeEvent } from '@progress/kendo-react-data-tools';
22+
23+
const DATA_ITEM_KEY = 'ID';
24+
const SELECTED_FIELD = 'selected';
25+
const idGetter = getter(DATA_ITEM_KEY);
26+
27+
interface SelectedState {
28+
[id: string]: boolean | number[];
29+
}
30+
31+
interface PageState {
32+
skip: number;
33+
take: number;
34+
}
35+
36+
const AdminView: React.FC = () => {
37+
const gridRef = React.useRef<GridHandle>(null);
38+
const [selectedState, setSelectedState] = React.useState<SelectedState>({});
39+
const [sort, setSort] = React.useState<{ field: string; dir: 'asc' | 'desc' }[]>([
40+
{ field: 'Sales', dir: 'desc' },
41+
]);
42+
const [showChartWizard, setShowChartWizard] = React.useState<boolean>(false);
43+
const [chartData, setChartData] = React.useState<SampleDataItem[]>([]);
44+
const [top3SalesData, setTop3SalesData] = React.useState<SampleDataItem[]>([]);
45+
const [top3Visible, setTop3Visible] = React.useState<boolean>(false);
46+
const [page, setPage] = React.useState<PageState>({ skip: 0, take: 4 });
47+
48+
const pageChange = (event: PageChangeEvent) => {
49+
setPage(event.page);
50+
};
51+
52+
const data = sampleData.map((item) => ({
53+
...item,
54+
[SELECTED_FIELD]: selectedState[idGetter(item)],
55+
}));
56+
57+
const pagedData = orderBy(data, sort).slice(page.skip, page.skip + page.take);
58+
59+
const onSelectionChange = (event: GridSelectionChangeEvent) => {
60+
const newSelectedState = getSelectedState({
61+
event,
62+
selectedState,
63+
dataItemKey: DATA_ITEM_KEY,
64+
});
65+
setSelectedState(newSelectedState);
66+
};
67+
68+
const onKeyDown = (event: GridKeyDownEvent) => {
69+
const newSelectedState = getSelectedStateFromKeyDown({
70+
event,
71+
selectedState,
72+
dataItemKey: DATA_ITEM_KEY,
73+
});
74+
setSelectedState(newSelectedState);
75+
};
76+
77+
const disabled = Object.keys(selectedState).length === 0;
78+
79+
const handleSelectedChart = React.useCallback(() => {
80+
if (gridRef.current) {
81+
const chartWizardData = getWizardDataFromGridSelection({
82+
grid: gridRef.current,
83+
data: sampleData,
84+
selectedState,
85+
dataItemKey: DATA_ITEM_KEY,
86+
});
87+
88+
setChartData(chartWizardData);
89+
setShowChartWizard(true);
90+
} else {
91+
console.error('Grid reference is not available.');
92+
}
93+
}, [selectedState]);
94+
95+
const handleTop3Sales = React.useCallback(() => {
96+
const selectedData = getWizardDataFromGridSelection({
97+
grid: gridRef.current,
98+
data: sampleData,
99+
selectedState,
100+
dataItemKey: DATA_ITEM_KEY,
101+
});
102+
103+
const sortedTop3Sales = selectedData
104+
.sort(
105+
(a, b) =>
106+
b.find((field) => field.field === 'Total Sales').value -
107+
a.find((field) => field.field === 'Total Sales').value
108+
)
109+
.slice(0, 3);
110+
111+
setTop3SalesData(sortedTop3Sales);
112+
setTop3Visible(true);
113+
}, [selectedState]);
114+
115+
const URLImageCell: React.FC<{ dataItem: SampleDataItem; field?: string }> = ({
116+
dataItem,
117+
field,
118+
}) => {
119+
const imageUrl = dataItem[field || 'URL'];
120+
return (
121+
<td>
122+
<img src={imageUrl} alt="Product" style={{ width: '100px', height: 'auto' }} />
123+
</td>
124+
);
125+
};
126+
127+
const MyPager: React.FC<{
128+
skip: number;
129+
take: number;
130+
total: number;
131+
onPageChange: (event: PageChangeEvent) => void;
132+
}> = (props) => {
133+
return (
134+
<div style={{ overflow: 'hidden', padding: '10px' }}>
135+
<Pager
136+
responsive={true}
137+
skip={props.skip}
138+
take={props.take}
139+
total={props.total}
140+
onPageChange={props.onPageChange}
141+
buttonCount={5}
142+
info={true}
143+
previousNext={true}
144+
type="numeric"
145+
pageSizes={[4, 10, 15, 20]}
146+
pageSizeValue={props.take}
147+
/>
148+
</div>
149+
);
150+
};
151+
152+
return (
153+
<>
154+
<div style={{ marginBottom: '10px' }}>
155+
<Button
156+
svgIcon={chartAreaStackedIcon}
157+
onClick={handleSelectedChart}
158+
disabled={disabled}
159+
style={{ marginRight: '10px' }}
160+
>
161+
Chart of Selected Data
162+
</Button>
163+
<Button svgIcon={chartAreaStackedIcon} onClick={handleTop3Sales}>
164+
Top 3 Sales per Category
165+
</Button>
166+
</div>
167+
<Grid
168+
ref={gridRef}
169+
style={{ height: '500px' }}
170+
data={pagedData}
171+
dataItemKey={DATA_ITEM_KEY}
172+
selectedField={SELECTED_FIELD}
173+
skip={page.skip}
174+
take={page.take}
175+
total={data.length}
176+
pageable={true}
177+
onPageChange={pageChange}
178+
pager={(pagerProps) => <MyPager {...pagerProps} />}
179+
selectable={{
180+
enabled: true,
181+
drag: true,
182+
mode: 'multiple',
183+
}}
184+
navigatable={true}
185+
onSelectionChange={onSelectionChange}
186+
onKeyDown={onKeyDown}
187+
sortable={true}
188+
sort={sort}
189+
onSortChange={(e: GridSortChangeEvent) => {
190+
setSort(e.sort);
191+
}}
192+
>
193+
<GridColumn field="URL" title="Product" cell={URLImageCell} />
194+
<GridColumn field="Product" title="Name" />
195+
<GridColumn field="SKU" title="SKU" />
196+
<GridColumn field="Category" title="Category" />
197+
<GridColumn field="Price" title="Price" />
198+
<GridColumn field="Quantity" title="Quantity" />
199+
<GridColumn field="Sales" title="Total Sales" />
200+
</Grid>
201+
202+
{showChartWizard && (
203+
<ChartWizard
204+
data={chartData}
205+
series={[
206+
{
207+
field: 'value',
208+
categoryField: 'category',
209+
},
210+
]}
211+
onClose={() => setShowChartWizard(false)}
212+
/>
213+
)}
214+
215+
{top3Visible && (
216+
<ChartWizard
217+
data={top3SalesData}
218+
series={[
219+
{
220+
field: 1,
221+
categoryField: 0,
222+
},
223+
]}
224+
onClose={() => setTop3Visible(false)}
225+
/>
226+
)}
227+
</>
228+
);
229+
};
230+
231+
export default AdminView;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import * as React from 'react';
2+
3+
import {
4+
DropDownList,
5+
DropDownListChangeEvent,
6+
} from '@progress/kendo-react-dropdowns';
7+
8+
const AppointmentInput: React.FC = () => {
9+
const appointments = [
10+
{ text: 'Customer Service Appointment', id: 1 },
11+
{ text: 'Sales Representative Appointment', id: 2 },
12+
{ text: 'Refund Appointment', id: 3 },
13+
];
14+
15+
const [state, setState] = React.useState({
16+
value: { text: 'Customer Service Appointment', id: 1 },
17+
});
18+
19+
const handleChange = (event: DropDownListChangeEvent) => {
20+
setState({
21+
value: event.target.value,
22+
});
23+
};
24+
25+
return (
26+
<DropDownList
27+
data={appointments}
28+
textField="text"
29+
dataItemKey="id"
30+
value={state.value}
31+
onChange={handleChange}
32+
/>
33+
);
34+
};
35+
36+
export default AppointmentInput;
37+

0 commit comments

Comments
 (0)