Add an accommodations reservations module #188

Merged
pierre merged 81 commits from accomodation_module into master 2024-06-22 21:30:26 +00:00
7 changed files with 164 additions and 3 deletions
Showing only changes of commit c8a01f11b2 - Show all commits

View File

@ -23,6 +23,7 @@
"@mui/lab": "^5.0.0-alpha.140", "@mui/lab": "^5.0.0-alpha.140",
"@mui/material": "^5.15.17", "@mui/material": "^5.15.17",
"@mui/x-data-grid": "^7.1.1", "@mui/x-data-grid": "^7.1.1",
"@mui/x-date-pickers": "^7.7.0",
"@mui/x-tree-view": "^7.4.0", "@mui/x-tree-view": "^7.4.0",
"@testing-library/jest-dom": "^6.4.5", "@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^16.0.0", "@testing-library/react": "^16.0.0",
@ -32,6 +33,7 @@
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"date-and-time": "^3.2.0", "date-and-time": "^3.2.0",
"dayjs": "^1.11.11",
"email-validator": "^2.0.4", "email-validator": "^2.0.4",
"filesize": "^10.1.2", "filesize": "^10.1.2",
"jspdf": "^2.5.1", "jspdf": "^2.5.1",
@ -1579,6 +1581,71 @@
"react-dom": "^17.0.0 || ^18.0.0" "react-dom": "^17.0.0 || ^18.0.0"
} }
}, },
"node_modules/@mui/x-date-pickers": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.7.0.tgz",
"integrity": "sha512-huyoA22Vi8iCkee6ro0sX7CcFIcPV/Fl7ZGWwaQC8PTAheXhz823DjMYAiwRU/imF+UFYfUInWQ4XZCIkM+2Dw==",
"dependencies": {
"@babel/runtime": "^7.24.7",
"@mui/base": "^5.0.0-beta.40",
"@mui/system": "^5.15.15",
"@mui/utils": "^5.15.14",
"@types/react-transition-group": "^4.4.10",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-transition-group": "^4.4.5"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@mui/material": "^5.15.14",
"date-fns": "^2.25.0 || ^3.2.0",
"date-fns-jalali": "^2.13.0-0 || ^3.2.0-0",
"dayjs": "^1.10.7",
"luxon": "^3.0.2",
"moment": "^2.29.4",
"moment-hijri": "^2.1.2",
"moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"date-fns": {
"optional": true
},
"date-fns-jalali": {
"optional": true
},
"dayjs": {
"optional": true
},
"luxon": {
"optional": true
},
"moment": {
"optional": true
},
"moment-hijri": {
"optional": true
},
"moment-jalaali": {
"optional": true
}
}
},
"node_modules/@mui/x-tree-view": { "node_modules/@mui/x-tree-view": {
"version": "7.7.0", "version": "7.7.0",
"resolved": "https://registry.npmjs.org/@mui/x-tree-view/-/x-tree-view-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@mui/x-tree-view/-/x-tree-view-7.7.0.tgz",
@ -2552,6 +2619,11 @@
"integrity": "sha512-UguWfh9LkUecVrGSE0B7SpAnGRMPATmpwSoSij24/lDnwET3A641abfDBD/TdL0T+E04f8NWlbMkD9BscVvIZg==", "integrity": "sha512-UguWfh9LkUecVrGSE0B7SpAnGRMPATmpwSoSij24/lDnwET3A641abfDBD/TdL0T+E04f8NWlbMkD9BscVvIZg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/dayjs": {
"version": "1.11.11",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz",
"integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg=="
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",

View File

@ -19,6 +19,7 @@
"@mui/lab": "^5.0.0-alpha.140", "@mui/lab": "^5.0.0-alpha.140",
"@mui/material": "^5.15.17", "@mui/material": "^5.15.17",
"@mui/x-data-grid": "^7.1.1", "@mui/x-data-grid": "^7.1.1",
"@mui/x-date-pickers": "^7.7.0",
"@mui/x-tree-view": "^7.4.0", "@mui/x-tree-view": "^7.4.0",
"@testing-library/jest-dom": "^6.4.5", "@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^16.0.0", "@testing-library/react": "^16.0.0",
@ -28,6 +29,7 @@
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"date-and-time": "^3.2.0", "date-and-time": "^3.2.0",
"dayjs": "^1.11.11",
"email-validator": "^2.0.4", "email-validator": "^2.0.4",
"filesize": "^10.1.2", "filesize": "^10.1.2",
"jspdf": "^2.5.1", "jspdf": "^2.5.1",

View File

@ -9,9 +9,9 @@ import React from "react";
import { ServerApi } from "../../api/ServerApi"; import { ServerApi } from "../../api/ServerApi";
import { NewCalendarURL } from "../../api/accommodations/AccommodationsCalendarURLApi"; import { NewCalendarURL } from "../../api/accommodations/AccommodationsCalendarURLApi";
import { checkConstraint } from "../../utils/from_utils"; import { checkConstraint } from "../../utils/from_utils";
import { useAccommodations } from "../../widgets/accommodations/BaseAccommodationsRoute";
import { PropEdit } from "../../widgets/forms/PropEdit"; import { PropEdit } from "../../widgets/forms/PropEdit";
import { PropSelect } from "../../widgets/forms/PropSelect"; import { PropSelect } from "../../widgets/forms/PropSelect";
import { useAccommodations } from "../../widgets/accommodations/BaseAccommodationsRoute";
export function CreateAccommodationCalendarURLDialog(p: { export function CreateAccommodationCalendarURLDialog(p: {
open: boolean; open: boolean;

View File

@ -8,6 +8,7 @@ import {
import React from "react"; import React from "react";
import { UpdateAccommodationReservation } from "../../api/accommodations/AccommodationsReservationsApi"; import { UpdateAccommodationReservation } from "../../api/accommodations/AccommodationsReservationsApi";
import { useAccommodations } from "../../widgets/accommodations/BaseAccommodationsRoute"; import { useAccommodations } from "../../widgets/accommodations/BaseAccommodationsRoute";
import { PropDateInput } from "../../widgets/forms/PropDateInput";
import { PropSelect } from "../../widgets/forms/PropSelect"; import { PropSelect } from "../../widgets/forms/PropSelect";
export function UpdateReservationDialog(p: { export function UpdateReservationDialog(p: {
@ -41,6 +42,8 @@ export function UpdateReservationDialog(p: {
if (!reservation) setReservation(p.reservation); if (!reservation) setReservation(p.reservation);
}, [p.open, p.reservation]); }, [p.open, p.reservation]);
// TODO : check availability
return ( return (
<Dialog open={p.open} onClose={cancel}> <Dialog open={p.open} onClose={cancel}>
<DialogTitle> <DialogTitle>
@ -66,6 +69,31 @@ export function UpdateReservationDialog(p: {
value={reservation?.accommodation_id?.toString()} value={reservation?.accommodation_id?.toString()}
/> />
<PropDateInput
editable
label="Date de début"
value={reservation?.start}
onChange={(s) => {
setReservation((r) => {
return { ...r!, start: s ?? -1 };
});
}}
/>
<PropDateInput
editable
label="Date de fin"
value={reservation?.end}
lastSecOfDay={true}
onChange={(s) => {
setReservation((r) => {
return { ...r!, end: s ?? -1 };
});
}}
/>
{/* Constraint start and end */}
{/* TODO : la suite */} {/* TODO : la suite */}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>

View File

@ -65,8 +65,8 @@ export function AccommodationsReservationsRoute(): React.ReactElement {
updateReservation( updateReservation(
{ {
accommodation_id: -1, accommodation_id: -1,
start: Math.floor(d.start.getDate() / 1000), start: Math.floor(d.start.getTime() / 1000),
end: Math.floor(d.end.getDate() / 1000), end: Math.floor(d.end.getTime() / 1000),
}, },
true true
); );

View File

@ -0,0 +1,6 @@
/**
* Get formatted UNIX date
*/
export function fmtUnixDate(time: number): string {
return new Date(time * 1000).toLocaleString("fr-FR");
}

View File

@ -0,0 +1,53 @@
import { LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
import dayjs from "dayjs";
import { fmtUnixDate } from "../../utils/time_utils";
import { PropEdit } from "./PropEdit";
export function PropDateInput(p: {
editable: boolean;
label: string;
value: number | undefined;
onChange: (v: number | undefined) => void;
lastSecOfDay?: boolean;
}): React.ReactElement {
let shiftV = p.value;
if (shiftV && p.lastSecOfDay) {
const d = new Date(shiftV * 1000);
if (d.getHours() === 0) {
shiftV -= 1;
}
}
if (!p.editable) {
if (!shiftV) return <></>;
return (
<PropEdit editable={false} label={p.label} value={fmtUnixDate(shiftV)} />
);
}
const value = dayjs(
shiftV && p.value! > 0 ? new Date(shiftV * 1000) : undefined
);
return (
<div style={{ margin: "10px auto" }}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DatePicker
label={p.label}
value={value}
onChange={(v) => {
if (v && p.lastSecOfDay) {
v.set("hours", 23);
v.set("minutes", 59);
v.set("seconds", 59);
}
p.onChange?.(v ? v.unix() : undefined);
}}
/>
</LocalizationProvider>
</div>
);
}