Skip to content

Commit 6a6b9b2

Browse files
up
1 parent 6bf7de5 commit 6a6b9b2

File tree

51 files changed

+1164
-672
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1164
-672
lines changed

VehicleShowroom/src/components/categoryMenu/CategoryMenu.js

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,28 @@ export default function CategoryMenu({ isVisible, closeHandler }) {
4343
const fetchLevel1Models = async () => {
4444
setLoading(true);
4545
try {
46-
const res = await VehicleModelService.get({ pageNumber: 1, pageSize: 100 });
46+
const res = await VehicleModelService.get({
47+
pageNumber: 1,
48+
pageSize: 100,
49+
});
4750
const models = res?.items?.filter((m) => m.level === 1) || [];
4851

4952
const enriched = await Promise.all(
5053
models.map(async (m) => {
51-
let photoUrl = m.photo || 'https://placehold.co/600x400?text=No+Image';
54+
let photoUrl =
55+
m.photo || 'https://placehold.co/600x400?text=No+Image';
5256
try {
53-
const photos = await VehiclePhotoService.getByModelNumber(m.modelNumber);
57+
const photos = await VehiclePhotoService.getByModelNumber(
58+
m.modelNumber,
59+
);
5460
const displayPhoto =
5561
photos.items?.find((p) => p.displayOrder === 0)?.photoUrl ||
5662
photos.items?.[0]?.photoUrl ||
5763
photos.items?.[0]?.url;
5864
if (displayPhoto) photoUrl = displayPhoto;
5965
} catch {}
6066
return { ...m, photo: photoUrl };
61-
})
67+
}),
6268
);
6369

6470
setAllModels(enriched);
@@ -87,11 +93,14 @@ export default function CategoryMenu({ isVisible, closeHandler }) {
8793

8894
const enrichedVariants = await Promise.all(
8995
variants.map(async (m) => {
90-
let photoUrl = m.photo || 'https://placehold.co/600x400?text=No+Image';
96+
let photoUrl =
97+
m.photo || 'https://placehold.co/600x400?text=No+Image';
9198
let fuelType = 'N/A';
9299

93100
try {
94-
const photos = await VehiclePhotoService.getByModelNumber(m.modelNumber);
101+
const photos = await VehiclePhotoService.getByModelNumber(
102+
m.modelNumber,
103+
);
95104
const displayPhoto =
96105
photos.items?.find((p) => p.displayOrder === 0)?.photoUrl ||
97106
photos.items?.[0]?.photoUrl ||
@@ -100,13 +109,17 @@ export default function CategoryMenu({ isVisible, closeHandler }) {
100109
} catch {}
101110

102111
try {
103-
const specs = await VehicleSpecService.getByModelNumber(m.modelNumber);
104-
const fuelSpec = specs.items.find((s) => s.specName === 'Fuel Type');
112+
const specs = await VehicleSpecService.getByModelNumber(
113+
m.modelNumber,
114+
);
115+
const fuelSpec = specs.items.find(
116+
(s) => s.specName === 'Fuel Type',
117+
);
105118
if (fuelSpec) fuelType = fuelSpec.specValue;
106119
} catch {}
107120

108121
return { ...m, photo: photoUrl, fuelType };
109-
})
122+
}),
110123
);
111124

112125
setDisplayedModels(enrichedVariants);
@@ -237,7 +250,7 @@ export default function CategoryMenu({ isVisible, closeHandler }) {
237250
top="0"
238251
left="0"
239252
h="100dvh"
240-
w={{ base: '100%', md: '30%' }}
253+
w={{ base: '100%', md: '50%', '2xl': '30%' }}
241254
bg={bgColor}
242255
color={textColor}
243256
shadow="xl"
@@ -247,7 +260,12 @@ export default function CategoryMenu({ isVisible, closeHandler }) {
247260
zIndex="1500"
248261
>
249262
{/* 🔹 Header */}
250-
<Flex justify="space-between" align="center" p={6} borderColor={borderColor}>
263+
<Flex
264+
justify="space-between"
265+
align="center"
266+
p={6}
267+
borderColor={borderColor}
268+
>
251269
{parentModel ? (
252270
<Flex align="center" gap={3}>
253271
<IconButton

VehicleShowroom/src/components/dialog/FeedbackDialog.js

Lines changed: 0 additions & 37 deletions
This file was deleted.

VehicleShowroom/src/components/fields/DatePicker.js

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState } from "react";
1+
import React, { useState } from 'react';
22
import {
33
FormControl,
44
FormLabel,
@@ -11,30 +11,41 @@ import {
1111
PopoverContent,
1212
PopoverBody,
1313
useColorModeValue,
14-
} from "@chakra-ui/react";
15-
import { CalendarIcon } from "@chakra-ui/icons";
16-
import MiniCalendar from "components/calendar/MiniCalendar";
14+
} from '@chakra-ui/react';
15+
import { CalendarIcon } from '@chakra-ui/icons';
16+
import MiniCalendar from 'components/calendar/MiniCalendar';
1717

1818
export function DatePicker({ label, value, onChange }) {
1919
const [isOpen, setIsOpen] = useState(false);
20-
const textColor = useColorModeValue("secondaryGray.900", "white");
20+
const textColor = useColorModeValue('secondaryGray.900', 'white');
2121

22-
// ✅ Chuẩn hóa hiển thị: nếu có value hợp lệ → format dd/MM/yyyy
23-
let displayValue = "";
22+
// Parse "yyyy-MM-dd" thành Date LOCAL (tránh UTC)
23+
const parseLocalDate = (str) => {
24+
if (!str) return null;
25+
const [y, m, d] = str.split('-').map(Number);
26+
return new Date(y, (m || 1) - 1, d || 1);
27+
};
28+
29+
// Hiển thị dd/MM/yyyy (từ local date)
30+
let displayValue = '';
2431
if (value) {
25-
const parsed = new Date(value);
26-
if (!isNaN(parsed)) {
27-
displayValue = parsed.toLocaleDateString("en-GB"); // dd/MM/yyyy
32+
const parsed = parseLocalDate(value);
33+
if (parsed && !isNaN(parsed)) {
34+
displayValue = parsed.toLocaleDateString('en-GB'); // dd/MM/yyyy
2835
}
2936
}
3037

31-
// Khi chọn ngày từ MiniCalendar
38+
// Khi chọn ngày → format yyyy-MM-dd (local, không UTC)
3239
const handleSelectDate = (date) => {
33-
const formatted = date.toISOString().split("T")[0]; // yyyy-MM-dd
34-
onChange(formatted);
40+
const y = date.getFullYear();
41+
const m = String(date.getMonth() + 1).padStart(2, '0');
42+
const d = String(date.getDate()).padStart(2, '0');
43+
onChange(`${y}-${m}-${d}`);
3544
setIsOpen(false);
3645
};
3746

47+
const selectedDate = value ? parseLocalDate(value) : new Date();
48+
3849
return (
3950
<FormControl isRequired>
4051
<FormLabel>{label}</FormLabel>
@@ -65,10 +76,18 @@ export function DatePicker({ label, value, onChange }) {
6576
</InputGroup>
6677
</PopoverTrigger>
6778

68-
<PopoverContent w="auto" border="none" boxShadow="xl" p={2}>
79+
{/* key={value} đảm bảo MiniCalendar remount khi value đổi */}
80+
<PopoverContent
81+
w="auto"
82+
border="none"
83+
boxShadow="xl"
84+
p={2}
85+
key={value || 'empty'}
86+
>
6987
<PopoverBody>
7088
<MiniCalendar
71-
value={value ? new Date(value) : new Date()}
89+
// Dùng local date đã parse, KHÔNG dùng new Date('yyyy-MM-dd') trực tiếp
90+
value={selectedDate}
7291
onChange={handleSelectDate}
7392
/>
7493
</PopoverBody>

VehicleShowroom/src/constants/ApiUrl.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ export const ApiUrl = {
2626
// 🛒 Orders
2727
ORDERS: {
2828
BASE: `${BASE_URL}/Orders`,
29+
BY_ID: (id) => `${BASE_URL}/Orders/${id}`,
2930
ASSIGN_VEHICLE: (id) => `${BASE_URL}/Orders/${id}/assign-vehicle`,
30-
CONFIRM: (id) => `${BASE_URL}/Orders/${id}/confirm`,
31-
COMPLETE: (id) => `${BASE_URL}/Orders/${id}/complete`,
31+
STATUS: (id) => `${BASE_URL}/Orders/${id}/status`,
3232
},
3333

3434
// 👤 Profile
@@ -79,7 +79,6 @@ export const ApiUrl = {
7979
BY_ID: (modelNumber) => `${BASE_URL}/VehicleModels/${modelNumber}`,
8080
BY_MODEL: (modelNumber) => `${BASE_URL}/VehicleModels/${modelNumber}`,
8181
BY_SLUG: (slug) => `${BASE_URL}/VehicleModels/slug/${slug}`,
82-
SEARCH: `${BASE_URL}/VehicleModels/search`,
8382
},
8483

8584
// 🖼 Vehicle Photos
@@ -94,12 +93,9 @@ export const ApiUrl = {
9493
// 🚗 Vehicles
9594
VEHICLES: {
9695
BASE: `${BASE_URL}/Vehicles`,
97-
WITH_MEDIA: `${BASE_URL}/Vehicles/with-media`,
9896
BY_ID: (id) => `${BASE_URL}/Vehicles/${id}`,
99-
BY_SLUG: (slug) => `${BASE_URL}/Vehicles/slug/${slug}`,
100-
SEARCH: `${BASE_URL}/Vehicles/search`,
101-
BULK_DELETE: `${BASE_URL}/Vehicles/bulk-delete`,
10297
STATUS: (id) => `${BASE_URL}/Vehicles/${id}/status`,
98+
LICENSE_PLATE: (id) => `${BASE_URL}/Vehicles/${id}/license-plate`,
10399
},
104100

105101
// ⚙ Vehicle Specs

VehicleShowroom/src/routes.js

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ import React from 'react';
33
import { Icon } from '@chakra-ui/react';
44

55
import {
6-
MdHome,
7-
MdAccountCircle,
6+
MdDashboard,
7+
MdPeopleAlt,
8+
MdBadge,
89
MdCategory,
9-
MdOutlineDirectionsCar,
10+
MdDirectionsCarFilled,
11+
MdShoppingCartCheckout,
12+
MdAssignment,
13+
MdBuildCircle,
1014
} from 'react-icons/md';
1115

1216
// Admin Imports
@@ -37,26 +41,22 @@ const routes = [
3741
{
3842
name: 'Main Dashboard',
3943
layout: '/admin',
40-
path: '/default',
41-
icon: <Icon as={MdHome} width="20px" height="20px" color="inherit" />,
44+
path: '/dashboard',
45+
icon: <Icon as={MdDashboard} width="20px" height="20px" color="inherit" />,
4246
component: <Dashboard />,
4347
},
4448
{
4549
name: 'Customer Management',
4650
layout: '/admin',
4751
path: '/customer-management',
48-
icon: (
49-
<Icon as={MdAccountCircle} width="20px" height="20px" color="inherit" />
50-
),
52+
icon: <Icon as={MdPeopleAlt} width="20px" height="20px" color="inherit" />,
5153
component: <CustomerManagement />,
5254
},
5355
{
5456
name: 'Employee Management',
5557
layout: '/admin',
5658
path: '/employee-management',
57-
icon: (
58-
<Icon as={MdAccountCircle} width="20px" height="20px" color="inherit" />
59-
),
59+
icon: <Icon as={MdBadge} width="20px" height="20px" color="inherit" />,
6060
component: <EmployeeManagement />,
6161
},
6262
{
@@ -72,7 +72,7 @@ const routes = [
7272
path: '/vehicle-management',
7373
icon: (
7474
<Icon
75-
as={MdOutlineDirectionsCar}
75+
as={MdDirectionsCarFilled}
7676
width="20px"
7777
height="20px"
7878
color="inherit"
@@ -86,7 +86,7 @@ const routes = [
8686
path: '/purchase-management',
8787
icon: (
8888
<Icon
89-
as={MdOutlineDirectionsCar}
89+
as={MdShoppingCartCheckout}
9090
width="20px"
9191
height="20px"
9292
color="inherit"
@@ -98,27 +98,15 @@ const routes = [
9898
name: 'Order Management',
9999
layout: '/admin',
100100
path: '/order-management',
101-
icon: (
102-
<Icon
103-
as={MdOutlineDirectionsCar}
104-
width="20px"
105-
height="20px"
106-
color="inherit"
107-
/>
108-
),
101+
icon: <Icon as={MdAssignment} width="20px" height="20px" color="inherit" />,
109102
component: <OrderManagement />,
110103
},
111104
{
112105
name: 'Service Management',
113106
layout: '/admin',
114107
path: '/service-management',
115108
icon: (
116-
<Icon
117-
as={MdOutlineDirectionsCar}
118-
width="20px"
119-
height="20px"
120-
color="inherit"
121-
/>
109+
<Icon as={MdBuildCircle} width="20px" height="20px" color="inherit" />
122110
),
123111
component: <ServiceOrderManagement />,
124112
},

VehicleShowroom/src/services/OrderService.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ const OrderService = {
99
return res.data;
1010
},
1111

12+
getById: async (id) => {
13+
const res = await ApiClient.get(ApiUrl.ORDERS.BY_ID(id));
14+
return res.data;
15+
},
16+
1217
// 🟣 Tạo Order mới
1318
create: async (data) => {
1419
const res = await ApiClient.post(ApiUrl.ORDERS.BASE, data);
@@ -25,7 +30,7 @@ const OrderService = {
2530
},
2631

2732
updateStatus: async (id, status) => {
28-
const res = await ApiClient.put(`${ApiUrl.ORDERS.BASE}/${id}/status`, {
33+
const res = await ApiClient.put(ApiUrl.ORDERS.STATUS(id), {
2934
status,
3035
});
3136
return res.data;

VehicleShowroom/src/services/ServiceOrderService.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@ const ServiceOrderService = {
1414
const response = await ApiClient.post(ApiUrl.SERVICE_ORDERS.BASE, data);
1515
return response.data;
1616
},
17-
18-
updateStatus: async (id, payload) => {
19-
const response = await ApiClient.put(
20-
ApiUrl.SERVICE_ORDERS.STATUS(id),
21-
payload,
22-
);
17+
18+
updateStatus: async (id, status) => {
19+
const response = await ApiClient.put(ApiUrl.SERVICE_ORDERS.STATUS(id), {
20+
status,
21+
});
2322
return response.data;
2423
},
2524
};

0 commit comments

Comments
 (0)