share calendar

master
alex 2024-02-04 22:52:57 +01:00
parent a819ab52bb
commit d5148f8c48
4 changed files with 180 additions and 8 deletions

View File

@ -269,7 +269,19 @@
"checkboxDeleteCalendars": "Kalender für Öffnungszeiten und Termine löschen (Alle Termine werden gelöscht und können nicht wiederhergestellt werden)",
"button": "Google Kalender trennen"
},
"calendarFrameCustomerView": "Terminkalenderansicht der Kunden"
"calendarFrameCustomerView": "Terminkalenderansicht der Kunden",
"modalShareCalendarLink": {
"title": "Kalender-Link teilen",
"shareButtons": {
"emailSubject": "Buchen Sie einen Termin bei uns",
"emailBody": "Hallo,\n\n nutzen Sie den folgenden Link, um unseren Kalender einzusehen und einen Termin zu buchen.\n\n{{link}}\n\nMit freundlichen Grüßen\n\n{{username}}",
"whatsAppBody": "Hallo, nutzen Sie den folgenden Link, um unseren Kalender einzusehen und einen Termin zu buchen.\n\n{{link}}\n\nMit freundlichen Grüßen\n\n{{username}}"
},
"info": "Geben Sie den folgenden Link an Ihre Kunden weiter, damit diese Ihren Kalender einsehen und Termine buchen können.",
"bookingPageLink": "Link zur Buchungsseite",
"embed": "Einbetten",
"embedInfo": "Binden Sie den Kalender mit folgendem Code in Ihre Website ein."
}
},
"storeSettings": {
"pageTitle": "Einstellungen"

View File

@ -272,7 +272,19 @@
"checkboxDeleteCalendars": "Delete calendar for opening hours and appointments (all appointments are deleted and cannot be restored)",
"button": "Unlink Google Calendar"
},
"calendarFrameCustomerView": "Appointment diary view of customers"
"calendarFrameCustomerView": "Appointment diary view of customers",
"modalShareCalendarLink": {
"title": "Share calendar link",
"shareButtons": {
"emailSubject": "Book an appointment with us",
"emailBody": "Hello,\n\nuse the following link to view our calendar and book an appointment.\n\n{{link}}\n\nBest regards\n\n{{username}}",
"whatsAppBody": "Hello, use the following link to view our calendar and book an appointment:\n\n{{link}}\n\nBest regards\n\n{{username}}"
},
"info": "Share the following link with your customers to allow them to view your calendar and book appointments.",
"bookingPageLink": "Booking page link",
"embed": "Embed",
"embedInfo": "Embed the calendar on your website with the following code."
}
},
"storeSettings": {
"pageTitle": "Settings"

View File

@ -2,8 +2,10 @@ import {
Button,
Card,
Col,
Flex,
Form,
Grid,
QRCode,
Result,
Row,
Space,
@ -34,8 +36,17 @@ import {
} from "../../../Components/MyRequestStateItem";
import MyModal, {
MyModalCloseConfirmButtonFooter,
MyModalOnlyCloseButtonFooter,
} from "../../../Components/MyModal";
import { useParams } from "react-router-dom";
import {
DownloadOutlined,
MailOutlined,
ShareAltOutlined,
WhatsAppOutlined,
} from "@ant-design/icons";
import Paragraph from "antd/es/typography/Paragraph";
import { useSideBarContext } from "../../../Contexts/SideBarContext";
const { useBreakpoint } = Grid;
@ -191,20 +202,22 @@ export default function StoreCalendar() {
</Col>
<Col xs={24}>
<Card title={t("calendar.calendarFrameCustomerView")}>
<CalendarFrame storeId={storeId} />
</Card>
<CalendarFrameCard storeId={storeId} />
</Col>
</Row>
</>
);
}
function CalendarFrame({ storeId }) {
function CalendarFrameCard({ storeId }) {
const { t } = useTranslation();
const [isLoading, setIsLoading] = useState(true);
return (
<>
<Card
title={t("calendar.calendarFrameCustomerView")}
extra={<ModalShareCalendarLink storeId={storeId} />}
>
{isLoading && (
<div
style={{
@ -225,6 +238,139 @@ function CalendarFrame({ storeId }) {
height={530}
src={`${Constants.EMBED_CALENDAR_ADDRESS}${storeId}`}
/>
</Card>
);
}
function ModalShareCalendarLink({ storeId }) {
const { t } = useTranslation();
const [isModalOpen, setIsModalOpen] = useState(false);
const sideBarContext = useSideBarContext();
const handleModalClose = () => setIsModalOpen(false);
const embedPreContent = `<button onclick="KKInnovation.openPopup({url: '${Constants.EMBED_CALENDAR_ADDRESS}${storeId}'});">
Termin Buchen
</button>
<script src="${Constants.EMBED_CALENDAR_SCRIPT_ADDRESS}" type="text/javascript" async></script>`;
const downloadQRCode = () => {
const canvas = document
.getElementById("calendar-qrcode")
?.querySelector("canvas");
if (canvas) {
const url = canvas.toDataURL();
const a = document.createElement("a");
a.download = "QRCode.png";
a.href = url;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
};
return (
<>
<ShareAltOutlined onClick={() => setIsModalOpen(true)} />
<MyModal
title={t("calendar.modalShareCalendarLink.title")}
isOpen={isModalOpen}
onCancel={handleModalClose}
footer={<MyModalOnlyCloseButtonFooter onCancel={handleModalClose} />}
>
<Space style={{ paddingBottom: 12 }}>
<MailOutlined
style={{ fontSize: 20 }}
onClick={() =>
window.open(
`mailto:?subject=${t(
"calendar.modalShareCalendarLink.shareButtons.emailSubject"
)}&body=${encodeURIComponent(
t("calendar.modalShareCalendarLink.shareButtons.emailBody", {
link: `<a href="${Constants.EMBED_CALENDAR_ADDRESS}${storeId}">${Constants.EMBED_CALENDAR_ADDRESS}${storeId}</a>`,
username: sideBarContext.username,
})
)}`,
"_self"
)
}
/>
<WhatsAppOutlined
style={{ fontSize: 20 }}
onClick={() =>
window.open(
`https://web.whatsapp.com/send?text=${encodeURIComponent(
t(
"calendar.modalShareCalendarLink.shareButtons.whatsAppBody",
{
link: `${Constants.EMBED_CALENDAR_ADDRESS}${storeId}`,
username: sideBarContext.username,
}
)
)}`
)
}
/>
</Space>
<div
id="calendar-qrcode"
style={{ paddingBottom: 12 }}
onClick={downloadQRCode}
>
<QRCode
value={`${Constants.EMBED_CALENDAR_ADDRESS}${storeId}`}
bgColor="#fff"
/>
</div>
<Flex vertical>
<Typography.Text strong>
{t("calendar.modalShareCalendarLink.info")}
</Typography.Text>
<Paragraph
style={{
display: "flex",
alignContent: "center",
alignItems: "center",
gap: 12,
}}
copyable={{
text: `${Constants.EMBED_CALENDAR_ADDRESS}${storeId}`,
}}
>
<pre style={{ flex: 1 }}>
{`${Constants.EMBED_CALENDAR_ADDRESS}${storeId}`}
</pre>
</Paragraph>
<Typography.Text strong>
{t("calendar.modalShareCalendarLink.embed")}
</Typography.Text>
<Typography.Text>
{t("calendar.modalShareCalendarLink.embedInfo")}
</Typography.Text>
<Paragraph
copyable={{
text: embedPreContent,
}}
style={{
display: "flex",
alignContent: "center",
alignItems: "center",
gap: 12,
}}
>
<pre style={{ flex: 1 }}>{embedPreContent}</pre>
</Paragraph>
</Flex>
</MyModal>
</>
);
}
@ -301,7 +447,7 @@ function CardPersonalCalendarSettings({ settings }) {
t: t,
})
.then(() => setRequestState(RequestState.SUCCESS))
.catch((errStatus) => setRequestState(RequestState.FAILED));
.catch(() => setRequestState(RequestState.FAILED));
}, 500);
}, [usingPrimaryCalendar, maxFutureBookingDays, minEarliestBookingTime]);

View File

@ -34,6 +34,8 @@ export const Constants = {
//STATIC_CONTENT_ADDRESS: staticContentAddress,
// WS_ADDRESS: wsAddress,
EMBED_CALENDAR_ADDRESS: "https://calendar.ex.umbach.dev/embed/?id=",
EMBED_CALENDAR_SCRIPT_ADDRESS:
"https://calendar.ex.umbach.dev/embedPopup/script.js",
ROUTE_PATHS: {
AUTHENTICATION: {
LOGIN: "/login",