Skip to content

Commit d2ab469

Browse files
authored
Merge pull request #9 from sametcn99/dev
Dev
2 parents 3ba4b68 + f62ab0e commit d2ab469

47 files changed

Lines changed: 2844 additions & 867 deletions

Some content is hidden

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

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "booking-calendar",
3-
"version": "1.1.4",
3+
"version": "1.1.5",
44
"private": true,
55
"scripts": {
66
"dev:server": "bun run --watch src/server/index.ts",

src/client/src/api.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,18 @@ export interface ApiVersionInfo {
9696
}
9797

9898
export interface ApiWebhookSettings {
99-
enabled: boolean;
100-
url: string;
101-
has_secret: boolean;
99+
outbound: {
100+
enabled: boolean;
101+
url: string;
102+
has_secret: boolean;
103+
};
104+
inbound: {
105+
enabled: boolean;
106+
endpoint: string;
107+
has_secret: boolean;
108+
scopes: string[];
109+
};
110+
supported_actions: string[];
102111
}
103112

104113
async function parseApiResponse<T>(response: Response): Promise<T> {
@@ -495,10 +504,22 @@ export const api = {
495504
"/admin/settings/webhook",
496505
).then((r) => r.data),
497506

507+
getWebhookSecret: (target: "outbound" | "inbound") =>
508+
request<{ success: boolean; data: { secret: string } }>(
509+
`/admin/settings/webhook/secret?target=${target}`,
510+
).then((r) => r.data.secret),
511+
498512
setWebhookSettings: (input: {
499-
enabled: boolean;
500-
url: string;
501-
secret?: string;
513+
outbound?: {
514+
enabled?: boolean;
515+
url?: string;
516+
secret?: string;
517+
};
518+
inbound?: {
519+
enabled?: boolean;
520+
secret?: string;
521+
scopes?: string[];
522+
};
502523
}) =>
503524
request<{ success: boolean; data: ApiWebhookSettings }>(
504525
"/admin/settings/webhook",

src/client/src/components/AdminLayout.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { useState } from "react";
1616
import { Outlet, useLocation, useNavigate } from "react-router-dom";
1717
import { useAuth } from "../context/AuthContext";
1818
import { useI18n } from "../context/I18nContext";
19+
import AppToaster from "./AppToaster";
1920

2021
export default function AdminLayout() {
2122
const [css] = useStyletron();
@@ -53,6 +54,8 @@ export default function AdminLayout() {
5354
backgroundColor: "var(--color-bg-primary)",
5455
})}
5556
>
57+
<AppToaster />
58+
5659
{/* Sidebar */}
5760
<nav
5861
className={css({
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { PLACEMENT, ToasterContainer } from "baseui/toast";
2+
3+
const TOAST_AUTO_HIDE_DURATION = 5000;
4+
5+
export default function AppToaster() {
6+
return (
7+
<ToasterContainer
8+
placement={PLACEMENT.bottomRight}
9+
autoHideDuration={TOAST_AUTO_HIDE_DURATION}
10+
/>
11+
);
12+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { useStyletron } from "baseui";
2+
import { Loader } from "lucide-react";
3+
4+
interface Props {
5+
label?: string;
6+
}
7+
8+
export default function PageLoadingSpinner({ label }: Props) {
9+
const [css] = useStyletron();
10+
11+
return (
12+
<div
13+
className={css({
14+
display: "flex",
15+
flexDirection: "column",
16+
alignItems: "center",
17+
justifyContent: "center",
18+
padding: "80px 24px",
19+
gap: "16px",
20+
})}
21+
>
22+
<Loader
23+
size={32}
24+
className={css({
25+
color: "var(--color-accent-500, #8b5cf6)",
26+
animationName: {
27+
from: { transform: "rotate(0deg)" },
28+
to: { transform: "rotate(360deg)" },
29+
} as unknown as string,
30+
animationDuration: "1s",
31+
animationTimingFunction: "linear",
32+
animationIterationCount: "infinite",
33+
})}
34+
/>
35+
{label && (
36+
<p
37+
className={css({
38+
fontSize: "14px",
39+
color: "var(--color-text-subtle)",
40+
margin: 0,
41+
})}
42+
>
43+
{label}
44+
</p>
45+
)}
46+
</div>
47+
);
48+
}

src/client/src/i18n/en.json

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@
250250
"emailNotificationsRequiresAdminEmail": "Set an admin email first to enable email notifications.",
251251
"emailNotificationsSaved": "Email notification setting saved",
252252
"webhook": "Webhook Notifications",
253-
"webhookDescription": "Mirror every push notification event to your webhook endpoint with signed delivery headers.",
253+
"webhookDescription": "Configure signed outbound events and inbound command execution for external system integrations.",
254+
"webhookOutboundTitle": "Outbound Events",
255+
"webhookOutboundDescription": "Publish slot, appointment, link, planner, community event, and push changes to an external webhook endpoint.",
254256
"webhookEnabled": "Webhook notifications are enabled",
255257
"webhookDisabled": "Webhook notifications are disabled",
256258
"webhookUrl": "Webhook URL",
@@ -259,11 +261,27 @@
259261
"webhookSecretHint": "Signature header format: sha256=<hmac>. Minimum 16 characters.",
260262
"webhookSecretPlaceholder": "Paste a long random secret",
261263
"webhookGenerateSecret": "Generate Random Secret",
264+
"webhookRevealSecret": "Reveal",
265+
"webhookHideSecret": "Hide",
262266
"webhookSecretConfigured": "A secret is already configured. Leave empty to keep it unchanged.",
267+
"webhookSecretHiddenHint": "Stored secrets are hidden after refresh for security. Enter a new value only if you want to replace it.",
263268
"webhookSave": "Save Webhook Settings",
264269
"webhookSaved": "Webhook settings saved",
265270
"webhookSendTest": "Send Test Event",
266271
"webhookTestSent": "Test webhook event sent",
272+
"webhookInboundTitle": "Inbound Commands",
273+
"webhookInboundDescription": "Allow signed external systems to run approved actions inside Booking Calendar without sharing the admin session.",
274+
"webhookInboundEnabled": "Inbound webhook commands are enabled",
275+
"webhookInboundDisabled": "Inbound webhook commands are disabled",
276+
"webhookInboundEndpoint": "Inbound Endpoint",
277+
"webhookInboundEndpointHint": "Send signed POST requests to this endpoint with action, params, and data fields.",
278+
"webhookInboundSecret": "Inbound Signing Secret",
279+
"webhookInboundSecretHint": "Use the same sha256=<hmac> header format based on timestamp.body. Minimum 16 characters.",
280+
"webhookInboundSecretPlaceholder": "Paste the secret used by the external command sender",
281+
"webhookInboundSecretConfigured": "An inbound secret is already configured. Leave empty to keep it unchanged.",
282+
"webhookInboundSecretHiddenHint": "Stored inbound secrets are hidden after refresh for security. Enter a new value only if you want to replace it.",
283+
"webhookInboundScopes": "Allowed Scopes",
284+
"webhookInboundScopesHint": "Only the checked action groups can be executed by inbound webhook commands.",
267285
"version": "Version",
268286
"versionDescription": "See your current app version and check if a newer GitHub release is available.",
269287
"currentVersion": "Current version",
@@ -332,6 +350,7 @@
332350
"plannerLegend": "Planner Events"
333351
},
334352
"common": {
353+
"loading": "Loading...",
335354
"error": "An error occurred",
336355
"confirmationTitle": "Please confirm",
337356
"confirmDeleteMessage": "Are you sure you want to delete this item?",

src/client/src/i18n/schema.json

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,12 @@
963963
"webhookDescription": {
964964
"type": "string"
965965
},
966+
"webhookOutboundTitle": {
967+
"type": "string"
968+
},
969+
"webhookOutboundDescription": {
970+
"type": "string"
971+
},
966972
"webhookEnabled": {
967973
"type": "string"
968974
},
@@ -987,9 +993,18 @@
987993
"webhookGenerateSecret": {
988994
"type": "string"
989995
},
996+
"webhookRevealSecret": {
997+
"type": "string"
998+
},
999+
"webhookHideSecret": {
1000+
"type": "string"
1001+
},
9901002
"webhookSecretConfigured": {
9911003
"type": "string"
9921004
},
1005+
"webhookSecretHiddenHint": {
1006+
"type": "string"
1007+
},
9931008
"webhookSave": {
9941009
"type": "string"
9951010
},
@@ -1002,6 +1017,45 @@
10021017
"webhookTestSent": {
10031018
"type": "string"
10041019
},
1020+
"webhookInboundTitle": {
1021+
"type": "string"
1022+
},
1023+
"webhookInboundDescription": {
1024+
"type": "string"
1025+
},
1026+
"webhookInboundEnabled": {
1027+
"type": "string"
1028+
},
1029+
"webhookInboundDisabled": {
1030+
"type": "string"
1031+
},
1032+
"webhookInboundEndpoint": {
1033+
"type": "string"
1034+
},
1035+
"webhookInboundEndpointHint": {
1036+
"type": "string"
1037+
},
1038+
"webhookInboundSecret": {
1039+
"type": "string"
1040+
},
1041+
"webhookInboundSecretHint": {
1042+
"type": "string"
1043+
},
1044+
"webhookInboundSecretPlaceholder": {
1045+
"type": "string"
1046+
},
1047+
"webhookInboundSecretConfigured": {
1048+
"type": "string"
1049+
},
1050+
"webhookInboundSecretHiddenHint": {
1051+
"type": "string"
1052+
},
1053+
"webhookInboundScopes": {
1054+
"type": "string"
1055+
},
1056+
"webhookInboundScopesHint": {
1057+
"type": "string"
1058+
},
10051059
"version": {
10061060
"type": "string"
10071061
},
@@ -1159,6 +1213,8 @@
11591213
"emailNotificationsSaved",
11601214
"webhook",
11611215
"webhookDescription",
1216+
"webhookOutboundTitle",
1217+
"webhookOutboundDescription",
11621218
"webhookEnabled",
11631219
"webhookDisabled",
11641220
"webhookUrl",
@@ -1167,11 +1223,27 @@
11671223
"webhookSecretHint",
11681224
"webhookSecretPlaceholder",
11691225
"webhookGenerateSecret",
1226+
"webhookRevealSecret",
1227+
"webhookHideSecret",
11701228
"webhookSecretConfigured",
1229+
"webhookSecretHiddenHint",
11711230
"webhookSave",
11721231
"webhookSaved",
11731232
"webhookSendTest",
11741233
"webhookTestSent",
1234+
"webhookInboundTitle",
1235+
"webhookInboundDescription",
1236+
"webhookInboundEnabled",
1237+
"webhookInboundDisabled",
1238+
"webhookInboundEndpoint",
1239+
"webhookInboundEndpointHint",
1240+
"webhookInboundSecret",
1241+
"webhookInboundSecretHint",
1242+
"webhookInboundSecretPlaceholder",
1243+
"webhookInboundSecretConfigured",
1244+
"webhookInboundSecretHiddenHint",
1245+
"webhookInboundScopes",
1246+
"webhookInboundScopesHint",
11751247
"version",
11761248
"versionDescription",
11771249
"currentVersion",
@@ -1331,6 +1403,9 @@
13311403
"common": {
13321404
"type": "object",
13331405
"properties": {
1406+
"loading": {
1407+
"type": "string"
1408+
},
13341409
"error": {
13351410
"type": "string"
13361411
},
@@ -1390,6 +1465,7 @@
13901465
}
13911466
},
13921467
"required": [
1468+
"loading",
13931469
"error",
13941470
"confirmationTitle",
13951471
"confirmDeleteMessage",

src/client/src/i18n/tr.json

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@
250250
"emailNotificationsRequiresAdminEmail": "E-posta bildirimlerini açmak için önce admin e-postası kaydedin.",
251251
"emailNotificationsSaved": "E-posta bildirim ayarı kaydedildi",
252252
"webhook": "Webhook Bildirimleri",
253-
"webhookDescription": "Her push bildirim olayını imzalı teslim başlıklarıyla webhook adresinize aynalar.",
253+
"webhookDescription": "Harici sistem entegrasyonları için imzalı dışa giden eventleri ve içe gelen komut yürütmesini yapılandırın.",
254+
"webhookOutboundTitle": "Dışa Giden Eventler",
255+
"webhookOutboundDescription": "Slot, randevu, bağlantı, planlayıcı, topluluk etkinliği ve push değişikliklerini harici webhook adresine yayınlayın.",
254256
"webhookEnabled": "Webhook bildirimleri etkin",
255257
"webhookDisabled": "Webhook bildirimleri devre dışı",
256258
"webhookUrl": "Webhook URL",
@@ -259,11 +261,27 @@
259261
"webhookSecretHint": "Imza basligi formati: sha256=<hmac>. Minimum 16 karakter.",
260262
"webhookSecretPlaceholder": "Uzun ve rastgele bir gizli anahtar girin",
261263
"webhookGenerateSecret": "Rastgele Gizli Anahtar Uret",
264+
"webhookRevealSecret": "Goster",
265+
"webhookHideSecret": "Gizle",
262266
"webhookSecretConfigured": "Bir gizli anahtar zaten kayıtlı. Aynı kalması için boş bırakın.",
267+
"webhookSecretHiddenHint": "Kayitli secret guvenlik nedeniyle sayfa yenilendikten sonra gosterilmez. Yalnizca degistirmek istiyorsaniz yeni bir deger girin.",
263268
"webhookSave": "Webhook Ayarlarını Kaydet",
264269
"webhookSaved": "Webhook ayarları kaydedildi",
265270
"webhookSendTest": "Test Olayı Gönder",
266271
"webhookTestSent": "Test webhook olayı gönderildi",
272+
"webhookInboundTitle": "İçe Gelen Komutlar",
273+
"webhookInboundDescription": "Admin oturumunu paylaşmadan, imzalı harici sistemlerin izin verilen aksiyonları Booking Calendar içinde çalıştırmasına izin verin.",
274+
"webhookInboundEnabled": "İçe gelen webhook komutları etkin",
275+
"webhookInboundDisabled": "İçe gelen webhook komutları devre dışı",
276+
"webhookInboundEndpoint": "İçe Gelen Endpoint",
277+
"webhookInboundEndpointHint": "Bu endpoint'e action, params ve data alanları içeren imzalı POST istekleri gönderin.",
278+
"webhookInboundSecret": "İçe Gelen İmzalama Gizli Anahtarı",
279+
"webhookInboundSecretHint": "timestamp.body tabanlı sha256=<hmac> başlık formatını kullanın. Minimum 16 karakter.",
280+
"webhookInboundSecretPlaceholder": "Harici komut göndericisinin kullanacağı gizli anahtarı girin",
281+
"webhookInboundSecretConfigured": "Bir inbound secret zaten kayıtlı. Aynı kalması için boş bırakın.",
282+
"webhookInboundSecretHiddenHint": "Kayitli inbound secret guvenlik nedeniyle sayfa yenilendikten sonra gosterilmez. Yalnizca degistirmek istiyorsaniz yeni bir deger girin.",
283+
"webhookInboundScopes": "İzinli Scope'lar",
284+
"webhookInboundScopesHint": "Yalnızca işaretlenen aksiyon grupları inbound webhook komutları tarafından çalıştırılabilir.",
267285
"version": "Sürüm",
268286
"versionDescription": "Mevcut uygulama sürümünüzü görün ve GitHub'da daha yeni bir release olup olmadığını kontrol edin.",
269287
"currentVersion": "Mevcut sürüm",
@@ -332,6 +350,7 @@
332350
"plannerLegend": "Planlayıcı Etkinlikleri"
333351
},
334352
"common": {
353+
"loading": "Yükleniyor...",
335354
"error": "Bir hata oluştu",
336355
"confirmationTitle": "Lütfen onaylayın",
337356
"confirmDeleteMessage": "Bu öğeyi silmek istediğinize emin misiniz?",

src/client/src/pages/AppointmentDetailPage/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { useStyletron } from "baseui";
22
import { Button, KIND, SIZE } from "baseui/button";
3-
import { PLACEMENT, ToasterContainer, toaster } from "baseui/toast";
3+
import { toaster } from "baseui/toast";
44
import { Copy } from "lucide-react";
55
import { useCallback, useEffect, useMemo, useState } from "react";
66
import { useParams } from "react-router-dom";
77
import { type ApiAppointment, api } from "../../api";
8+
import AppToaster from "../../components/AppToaster";
89
import ConfirmationDialog from "../../components/ConfirmationDialog";
910
import { useI18n } from "../../context/I18nContext";
1011

@@ -119,7 +120,7 @@ export default function AppointmentDetailPage() {
119120
justifyContent: "center",
120121
})}
121122
>
122-
<ToasterContainer placement={PLACEMENT.bottomRight} />
123+
<AppToaster />
123124

124125
<div
125126
className={css({

0 commit comments

Comments
 (0)