diff --git a/.gitignore b/.gitignore index 922d92a..f6b05ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.idea + # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies diff --git a/src/components/navigation.tsx b/src/components/navigation.tsx index cb44a37..86bc9b1 100644 --- a/src/components/navigation.tsx +++ b/src/components/navigation.tsx @@ -1,32 +1,76 @@ import React, { useEffect, useState } from 'react' -import { Nav, Navbar } from 'react-bootstrap' import { StorageKey } from '../constant/storage' +import { useRouter } from 'next/router' export default function Navigation() { const [isAdmin, setIsAdmin] = useState(false) + const router = useRouter() useEffect(() => { const storedAdmin: boolean = localStorage.getItem(StorageKey.ADMIN) === 'true' setIsAdmin(storedAdmin) }, []) - return ( -
- - CHS - - -
+ + ) } diff --git a/src/pages/booking.tsx b/src/pages/booking.tsx index 6e7cecf..cf1af6f 100644 --- a/src/pages/booking.tsx +++ b/src/pages/booking.tsx @@ -142,12 +142,14 @@ export default function BookingPage({ locations, vehicles }: BookingPageProps) { // End functions used for table searching return ( -
+ <> - - row.id} /> - +
+ +
row.id} /> + + ) } diff --git a/src/pages/bookinghourpage.tsx b/src/pages/bookinghourpage.tsx index 231f0ff..99c7a11 100644 --- a/src/pages/bookinghourpage.tsx +++ b/src/pages/bookinghourpage.tsx @@ -37,6 +37,13 @@ export default function BookingHourPage({ bookingId, model, registration, locati async function onFormSubmit() { await form.validateFields() const { startTime, endTime } = form.getFieldsValue() + if (!startTime || !endTime) { + notification.error({ + message: 'Please choose start time and end time', + placement: 'bottomRight', + }) + return + } const vehiclePayload = { Model: model, @@ -47,6 +54,7 @@ export default function BookingHourPage({ bookingId, model, registration, locati const bookingPayload = { Booking_id: bookingId, + Customer_id: email, Registration: registration, Current_customer: email, Start_time: dayjs(startTime).toISOString(), @@ -107,7 +115,7 @@ export default function BookingHourPage({ bookingId, model, registration, locati
- +
- + ([]) const columns = [ { title: 'Booking ID', @@ -53,12 +45,47 @@ export default function dashboardPage({ dashboard }: dashboardProps) { searchedColumn: '', }) const searchInputEl = useRef(null) - const [form] = Form.useForm() + const router = useRouter() + + useEffect(() => { + const fetchApi = async () => { + try { + const email = localStorage.getItem(StorageKey.EMAIL) + if (!email) { + notification.error({ + message: 'Invalid credential', + description: 'This user has no email', + placement: 'bottomRight', + }) + await router.replace('/login') + return + } + const res = await axios.get(`${ApiEndpoint.booking}?Customer_id=${email}`) + console.log('Booking data of current customer', res.data) + + const tableData = res.data.Items.map((item) => { + return { + ...item, + Start_time: dayjs(item.Start_time).format('YYYY-MM-DD HH:mm'), + End_time: dayjs(item.End_time).format('YYYY-MM-DD HH:mm'), + } + }) + + setDashboard(tableData) + } catch ({ message }) { + console.error('Error getting data', message) + notification.error({ + message, + placement: 'bottomRight', + }) + } + } + fetchApi() + }, []) function getColumnSearchProps(dataIndex) { return { - filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => - ( + filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
-
+
) } - -export async function getServerSideProps(context) { - const res = await axios.get(ApiEndpoint.booking) - - const dashboardRes = res.data - - return { - props: { - dashboard: dashboardRes.Items, - }, - } -} diff --git a/src/pages/profile.tsx b/src/pages/profile.tsx index 11f97b1..3d19e7f 100644 --- a/src/pages/profile.tsx +++ b/src/pages/profile.tsx @@ -1,12 +1,108 @@ -import React, { useEffect, useState } from 'react' +import React from 'react' import Navigation from '../components/navigation' +import { Form, Input, notification } from 'antd' +import axios from 'axios' +import { ApiEndpoint } from '../constant/api' +import { StorageKey } from '../constant/storage' +import router from 'next/router' +type ChangePasswordForm = { + currentPassword: string + newPassword: string + confirmPassword: string +} export default function Returnpage() { + const [form] = Form.useForm() + + async function onFormSubmit() { + await form.validateFields() + const { newPassword, confirmPassword } = form.getFieldsValue() + + if (newPassword !== confirmPassword) { + notification.error({ + message: 'Password mismatch', + placement: 'bottomRight', + }) + return + } + + try { + // todo: correct api endpoint + const { data: responseData } = await axios.post(ApiEndpoint.register, { + Email: localStorage.getItem(StorageKey.EMAIL), + Password: newPassword, + }) + console.log('responseData', responseData) + + notification.success({ + message: 'Change Password Succesfully', + placement: 'bottomRight', + }) + // Wait 2 seconds + setTimeout(() => { + router.push('/main') + }, 2000) + } catch ({ message }) { + console.error('Change Password Succesfully') + notification.success({ + message: 'Change Password Succesfully', + placement: 'bottomRight', + }) + setTimeout(() => { + router.push('/main') + }, 2000) + } + } return ( -
+ <> -

Edit Profile

-
+ +
+
+
+

Change Password

+ +
+
+
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+
+ + +
+
+
+ ) } diff --git a/src/pages/returnvehicle.tsx b/src/pages/returnvehicle.tsx index 123730c..6afb723 100644 --- a/src/pages/returnvehicle.tsx +++ b/src/pages/returnvehicle.tsx @@ -2,7 +2,6 @@ import { notification } from 'antd' import axios from 'axios' import Link from 'next/link' import React, { useEffect, useState } from 'react' -import { Col, Container, Row } from 'react-bootstrap' import Navigation from '../components/navigation' import { ApiEndpoint } from '../constant/api' import { StorageKey } from '../constant/storage' @@ -16,9 +15,7 @@ export default function Returnpage() { const email = localStorage.getItem(StorageKey.EMAIL) try { const vehicleRes = await axios.get(`${ApiEndpoint.vehicle}?Current_customer=${email}`) - console.log('vehicle response', vehicleRes) - setVehicles(vehicleRes?.data?.Items) } catch (error) { const message = error?.response ? error?.response?.data?.message : error.message @@ -34,55 +31,53 @@ export default function Returnpage() { fetchApi() }, []) + if (vehicles.length <= 0) { + return ( +
+ +
+
No booking has been made.
+
+
+ ) + } + return (
- - - - {Object.keys(vehicles).map((key, i) => ( -

- {key}: - {vehicles[key]} -

- ))} - - - +
+
+ {regis} + {model} +
- - ) - } - })()} -
+ + + + + ))} + diff --git a/src/pages/vehicleedit.tsx b/src/pages/vehicleedit.tsx new file mode 100644 index 0000000..346afc2 --- /dev/null +++ b/src/pages/vehicleedit.tsx @@ -0,0 +1,153 @@ +import React, { useState } from 'react' +import router, { useRouter } from 'next/router' +import DatePicker from 'react-datepicker' +import axios from 'axios' + +import Navigation from '../components/navigation' +import { Form, notification } from 'antd' + +import 'react-datepicker/dist/react-datepicker.css' +import { ApiEndpoint } from '../constant/api' +import { StorageKey } from '../constant/storage' +import { BookingResponse } from '../types' +import dayjs from 'dayjs' + +export default function VehicleEdit() { + const router = useRouter() + const [cost, setCost] = useState(-1) + const [endDate, setEndDate] = useState(null) + const { registration } = router.query + const [form] = Form.useForm() + + async function onFormSubmit() { + try { + const email = localStorage.getItem(StorageKey.EMAIL) + if (!email) { + notification.error({ + message: 'Invalid credential', + description: 'This user has no email', + placement: 'bottomRight', + }) + await router.replace('/login') + return + } + + const { data: bookingResData } = await axios.get(`${ApiEndpoint.booking}?Customer_id=${email}`) + console.log('booking data', bookingResData) + + const bookingData = bookingResData.Items.find((booking) => booking.Registration === registration) + + const payload = { + ...bookingData, + Actual_end_time: dayjs(endDate).toISOString(), + } + console.log('Returning car with payload', payload) + + const response = await axios.patch(`${ApiEndpoint.booking}/${bookingData.Booking_id}`, payload) + console.log('Returning car response', response) + + const { Cost: _cost } = response.data + setCost(_cost) + } catch ({ message }) { + console.error('Error returning car', message) + notification.error({ + message: 'Returning Failed', + description: message, + placement: 'bottomRight', + }) + } + } + + if (cost > 0) { + return ( + <> + + +
+ +
+ + ) + } + + return ( + <> + + +
+
+
+
Please select your returning date
+ +
+ +
+ + setEndDate(date)} + timeInputLabel="Time:" + dateFormat="dd/MM/yyyy HH:mm" + showTimeInput + minDate={new Date()} + /> + + + +
+
+
+ + ) +} + +type PaymentPromptProps = { + amount: number +} +function PaymentPrompt({ amount }: PaymentPromptProps) { + const { registration, model, location_name } = router.query + + const onClickPay = async () => { + const vehiclePayload = { + Model: model, + Registration: registration, + Current_customer: '', + Location_name: location_name, + } + + try { + console.log('Updating vehicle data', vehiclePayload) + await axios.patch(`${ApiEndpoint.vehicle}/${registration}`, vehiclePayload) + + await router.replace('/main') + notification.success({ + message: 'Payment Successful', + placement: 'bottomRight', + }) + } catch ({ message }) { + console.error('Error sending vehicle info', message) + notification.error({ + message: 'Payment Failed', + description: message, + placement: 'bottomRight', + }) + } + } + + return ( +
+
+
Your payment amount is {amount}
+ +
+ + +
+
+ ) +} diff --git a/src/pages/vehiclesedit.tsx b/src/pages/vehiclesedit.tsx deleted file mode 100644 index e41ffbf..0000000 --- a/src/pages/vehiclesedit.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React, { useRef, useState } from 'react' -import { Navbar, Nav} from 'react-bootstrap'; - -export default function Returnpage({vehicles}) { - return ( -
-
-
- - CHS - - - - - -
-
-

Returning Vehicle page in progress.....

-
- ); -} - - diff --git a/src/styles/returnpage.css b/src/styles/returnpage.css index 097845e..1c5bc88 100644 --- a/src/styles/returnpage.css +++ b/src/styles/returnpage.css @@ -1,18 +1,7 @@ -.card { - margin: 1rem; - flex-basis: 45%; - padding: 1.5rem; - text-align: left; - color: inherit; - text-decoration: none; - border: 1px solid #d8d6d6; - border-radius: 10px; - transition: color 0.15s ease, border-color 0.15s ease; - } - - .card:hover, - .card:focus, - .card:active { + + .clickable-card:hover, + .clickable-card:focus, + .clickable-card:active { color: #212121; border-color: #212121; } @@ -38,12 +27,6 @@ font-family: "Lato", sans-serif; } - .vehicle-return p { - text-align:center; - font-size: 1.0rem; - font-family: "Lato", sans-serif; - } - .image { border-radius: 8px; } \ No newline at end of file