diff --git a/geneit_app/package-lock.json b/geneit_app/package-lock.json
index ef5ee26..e179448 100644
--- a/geneit_app/package-lock.json
+++ b/geneit_app/package-lock.json
@@ -33,6 +33,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-easy-crop": "^5.0.7",
+ "react-qr-code": "^2.0.14",
"react-router-dom": "^6.23.1",
"react-zoom-pan-pinch": "^3.4.4",
"svg2pdf.js": "^2.2.3",
@@ -3483,6 +3484,11 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "node_modules/qr.js": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz",
+ "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ=="
+ },
"node_modules/raf": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
@@ -3533,6 +3539,24 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
},
+ "node_modules/react-qr-code": {
+ "version": "2.0.14",
+ "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.14.tgz",
+ "integrity": "sha512-xvAUqmXzFzf7X6aQAAKb6T02YYk9grBBFeqpp1MiVhUAKG3Rg9+hFiOKRYg4+rWc2MiXNxkri0ulAJgS12xh7Q==",
+ "dependencies": {
+ "prop-types": "^15.8.1",
+ "qr.js": "0.0.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native-svg": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native-svg": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-refresh": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
diff --git a/geneit_app/package.json b/geneit_app/package.json
index 4259423..2730de4 100644
--- a/geneit_app/package.json
+++ b/geneit_app/package.json
@@ -29,6 +29,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-easy-crop": "^5.0.7",
+ "react-qr-code": "^2.0.14",
"react-router-dom": "^6.23.1",
"react-zoom-pan-pinch": "^3.4.4",
"svg2pdf.js": "^2.2.3",
diff --git a/geneit_app/src/api/accommodations/AccommodationsCalendarURLApi.tsx b/geneit_app/src/api/accommodations/AccommodationsCalendarURLApi.tsx
index 7a1d27d..b898904 100644
--- a/geneit_app/src/api/accommodations/AccommodationsCalendarURLApi.tsx
+++ b/geneit_app/src/api/accommodations/AccommodationsCalendarURLApi.tsx
@@ -33,4 +33,11 @@ export class AccommodationsCalendarURLApi {
})
).data;
}
+
+ /**
+ * Get accommodation calendar URL route
+ */
+ static CalendarURL(c: AccommodationCalendarURL): string {
+ return `${APIClient.backendURL()}/acccommodations_calendar/${c.token}`;
+ }
}
diff --git a/geneit_app/src/dialogs/accommodations/InstallCalendarDialog.tsx b/geneit_app/src/dialogs/accommodations/InstallCalendarDialog.tsx
new file mode 100644
index 0000000..bddd61d
--- /dev/null
+++ b/geneit_app/src/dialogs/accommodations/InstallCalendarDialog.tsx
@@ -0,0 +1,76 @@
+import {
+ Dialog,
+ DialogTitle,
+ DialogContent,
+ DialogContentText,
+ DialogActions,
+ Button,
+ Typography,
+ FormControl,
+ IconButton,
+ InputAdornment,
+ InputLabel,
+ OutlinedInput,
+} from "@mui/material";
+import {
+ AccommodationCalendarURL,
+ AccommodationsCalendarURLApi,
+} from "../../api/accommodations/AccommodationsCalendarURLApi";
+import { VisibilityOff, Visibility } from "@mui/icons-material";
+import ContentCopyIcon from "@mui/icons-material/ContentCopy";
+import { CopyToClipboard } from "../../widgets/CopyToClipboard";
+import QRCode from "react-qr-code";
+
+export function InstallCalendarDialog(p: {
+ cal?: AccommodationCalendarURL;
+ onClose: () => void;
+}): React.ReactElement {
+ if (!p.cal) return <>>;
+
+ return (
+
+ );
+}
diff --git a/geneit_app/src/hooks/context_providers/accommodations/InstallCalendarDialogProvider.tsx b/geneit_app/src/hooks/context_providers/accommodations/InstallCalendarDialogProvider.tsx
new file mode 100644
index 0000000..61d05cd
--- /dev/null
+++ b/geneit_app/src/hooks/context_providers/accommodations/InstallCalendarDialogProvider.tsx
@@ -0,0 +1,44 @@
+import React, { PropsWithChildren } from "react";
+import { AccommodationCalendarURL } from "../../../api/accommodations/AccommodationsCalendarURLApi";
+import { InstallCalendarDialog } from "../../../dialogs/accommodations/InstallCalendarDialog";
+
+type DialogContext = (cal: AccommodationCalendarURL) => Promise;
+
+const DialogContextK = React.createContext(null);
+
+export function InstallCalendarDialogProvider(
+ p: PropsWithChildren
+): React.ReactElement {
+ const [cal, setCal] = React.useState();
+
+ const cb = React.useRef void)>(null);
+
+ const handleClose = () => {
+ setCal(undefined);
+
+ if (cb.current !== null) cb.current();
+ cb.current = null;
+ };
+
+ const hook: DialogContext = (c) => {
+ setCal(c);
+
+ return new Promise((res) => {
+ cb.current = res;
+ });
+ };
+
+ return (
+ <>
+
+ {p.children}
+
+
+ {cal && }
+ >
+ );
+}
+
+export function useInstallCalendarDialog(): DialogContext {
+ return React.useContext(DialogContextK)!;
+}
diff --git a/geneit_app/src/routes/family/accommodations/AccommodationsSettingsRoute.tsx b/geneit_app/src/routes/family/accommodations/AccommodationsSettingsRoute.tsx
index dfb4495..534c51d 100644
--- a/geneit_app/src/routes/family/accommodations/AccommodationsSettingsRoute.tsx
+++ b/geneit_app/src/routes/family/accommodations/AccommodationsSettingsRoute.tsx
@@ -24,6 +24,8 @@ import { TimeWidget } from "../../../widgets/TimeWidget";
import { useAccommodations } from "../../../widgets/accommodations/BaseAccommodationsRoute";
import { useCreateAccommodationCalendarURL } from "../../../hooks/context_providers/accommodations/CreateAccommodationCalendarURLDialogProvider";
import { AccommodationsCalendarURLApi } from "../../../api/accommodations/AccommodationsCalendarURLApi";
+import { useInstallCalendarDialog } from "../../../hooks/context_providers/accommodations/InstallCalendarDialogProvider";
+import { InstallCalendarDialog } from "../../../dialogs/accommodations/InstallCalendarDialog";
export function AccommodationsSettingsRoute(): React.ReactElement {
return (
@@ -224,6 +226,7 @@ function AccommodationsCalURLsCard(): React.ReactElement {
const family = useFamily();
const createCalendarURLDialog = useCreateAccommodationCalendarURL();
+ const calendarURLDialog = useInstallCalendarDialog();
const createCalendarURL = async () => {
try {
@@ -241,8 +244,8 @@ function AccommodationsCalURLsCard(): React.ReactElement {
setSuccess("Le calendrier a été créé avec succès !");
// TODO : reload URLS list
- // TODO : show QrCode dialog
- console.log(cal);
+
+ calendarURLDialog(cal);
} catch (e) {
console.error("Failed to create new accommodation calendar URL!", e);
setError(`Échec de la création du calendrier! ${e}`);
diff --git a/geneit_app/src/widgets/CopyToClipboard.tsx b/geneit_app/src/widgets/CopyToClipboard.tsx
new file mode 100644
index 0000000..72ea019
--- /dev/null
+++ b/geneit_app/src/widgets/CopyToClipboard.tsx
@@ -0,0 +1,30 @@
+import { ButtonBase } from "@mui/material";
+import { PropsWithChildren } from "react";
+import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
+
+export function CopyToClipboard(
+ p: PropsWithChildren<{ content: string }>
+): React.ReactElement {
+ const snackbar = useSnackbar();
+
+ const copy = () => {
+ navigator.clipboard.writeText(p.content);
+ snackbar(`${p.content} copied to clipboard.`);
+ };
+
+ return (
+
+ {p.children}
+
+ );
+}
diff --git a/geneit_app/src/widgets/accommodations/BaseAccommodationsRoute.tsx b/geneit_app/src/widgets/accommodations/BaseAccommodationsRoute.tsx
index 9516652..5e6b24b 100644
--- a/geneit_app/src/widgets/accommodations/BaseAccommodationsRoute.tsx
+++ b/geneit_app/src/widgets/accommodations/BaseAccommodationsRoute.tsx
@@ -8,6 +8,7 @@ import { CreateAccommodationCalendarURLDialogProvider } from "../../hooks/contex
import { UpdateAccommodationDialogProvider } from "../../hooks/context_providers/accommodations/UpdateAccommodationDialogProvider";
import { AsyncWidget } from "../AsyncWidget";
import { useFamily } from "../BaseFamilyRoute";
+import { InstallCalendarDialogProvider } from "../../hooks/context_providers/accommodations/InstallCalendarDialogProvider";
interface AccommodationsContext {
accommodations: AccommodationsList;
@@ -63,7 +64,9 @@ export function BaseAccommodationsRoute(): React.ReactElement {
>
-
+
+
+