diff --git a/frontend/assets/css/colors.scss b/frontend/assets/css/colors.scss index c422961f7..bacec1f66 100644 --- a/frontend/assets/css/colors.scss +++ b/frontend/assets/css/colors.scss @@ -1,6 +1,7 @@ // When updating values here, please keep in mind that you might have to updated utils/colors.ts too :root { + --dark-dark-grey: #5C4E4E; --white: #ffffff; --grey: #a5a5a5; --medium-grey: #b3b3b3; @@ -11,6 +12,7 @@ --light-grey-3: #d3d3d3; --light-grey-4: #dddddd; --light-grey-5: #eaeaea; + --light-grey-7: #C0C0C0; --dark-grey: #5c4e4e; --very-dark-grey: #362f32; --asphalt: #484f56; @@ -51,6 +53,7 @@ --text-color-inverted: var(--light-grey); --text-color-disabled: var(--grey); --text-color-discreet: var(--dark-grey); + --text-color--error: var(--flashy-red); --button-color-active: var(--primary-orange); --button-color-hover: var(--primary-orange-hover); @@ -63,6 +66,11 @@ --button-text-color-disabled: var(--grey-4); --button-text-color-dangerous: var(--white); + --button-secondary-background-color: var(--light-grey); + --button-secondary-background-color--hover: var(--light-grey-4 ); + --button-secondary-color: var(--light-black); + --button-secondary-border-color: var(--light-grey-7); + --checkbox-background-color: var(--light-grey-4); --container-background: var(--grey-4); @@ -146,9 +154,15 @@ --button-color-dark-pattern: var(--light-grey); --button-text-color-disabled: var(--light-grey); --button-text-color-dangerous: var(--light-grey); - - --checkbox-background-color: var(--light-grey); - + + --button-secondary-background-color: var(--very-dark-grey); + --button-secondary-background-color--hover: var(--light-black); + --button-secondary-color: var(--light-grey); + --button-secondary-border-color: var(--dark-dark-grey); + + --checkbox-background-color: var(--very-dark-grey); + --checkbox-border-color: var(--dark-grey); + --container-background: var(--light-black); --container-color: var(--grey-4); --container-border-color: var(--dark-grey); diff --git a/frontend/assets/css/prime.scss b/frontend/assets/css/prime.scss index bef2f4554..b21de51cb 100644 --- a/frontend/assets/css/prime.scss +++ b/frontend/assets/css/prime.scss @@ -160,6 +160,7 @@ width: 20px; height: 20px; border-radius: var(--border-radius); + border: 1px solid var(--checkbox-border-color); background: var(--checkbox-background-color); &.p-highlight:not(:hover) { background: var(--primary-color); diff --git a/frontend/components/bc/BcButton.vue b/frontend/components/bc/BcButton.vue new file mode 100644 index 000000000..bb5a711d2 --- /dev/null +++ b/frontend/components/bc/BcButton.vue @@ -0,0 +1,68 @@ + + + + + \ No newline at end of file diff --git a/frontend/components/bc/BcTooltip.vue b/frontend/components/bc/BcTooltip.vue index 131a94525..4efe718a5 100644 --- a/frontend/components/bc/BcTooltip.vue +++ b/frontend/components/bc/BcTooltip.vue @@ -13,8 +13,12 @@ interface Props { scrollContainer?: string // query selector for scrollable parent container dontOpenPermanently?: boolean hoverDelay?: number + tooltipWidth?: `${number}px` | `${number}%` + tooltipTextAlign?: 'left' | 'center' | 'right' } +const toolTipTextAlignWithDefault = computed(() => props.tooltipTextAlign || 'center') + const props = defineProps() const bcTooltipOwner = ref(null) const bcTooltip = ref(null) @@ -222,14 +226,14 @@ onUnmounted(() => { > -
+
@@ -296,7 +300,7 @@ onUnmounted(() => { flex-wrap: wrap; opacity: 0; transition: opacity 1s; - text-align: center; + text-align: v-bind(toolTipTextAlignWithDefault); padding: 9px 12px; border-radius: var(--border-radius); background: var(--tt-bg-color); diff --git a/frontend/components/bc/form/BcForm.vue b/frontend/components/bc/form/BcForm.vue new file mode 100644 index 000000000..1d68559f9 --- /dev/null +++ b/frontend/components/bc/form/BcForm.vue @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/frontend/components/bc/form/BcFormRow.vue b/frontend/components/bc/form/BcFormRow.vue new file mode 100644 index 000000000..3fcd8f386 --- /dev/null +++ b/frontend/components/bc/form/BcFormRow.vue @@ -0,0 +1,23 @@ + + + + + \ No newline at end of file diff --git a/frontend/components/bc/input/BcInputCheckbox.vue b/frontend/components/bc/input/BcInputCheckbox.vue new file mode 100644 index 000000000..ec4936aba --- /dev/null +++ b/frontend/components/bc/input/BcInputCheckbox.vue @@ -0,0 +1,58 @@ + + + + + \ No newline at end of file diff --git a/frontend/components/bc/input/BcInputError.vue b/frontend/components/bc/input/BcInputError.vue new file mode 100644 index 000000000..874a69d3e --- /dev/null +++ b/frontend/components/bc/input/BcInputError.vue @@ -0,0 +1,32 @@ + + + + + \ No newline at end of file diff --git a/frontend/components/bc/input/BcInputText.vue b/frontend/components/bc/input/BcInputText.vue new file mode 100644 index 000000000..de7219aec --- /dev/null +++ b/frontend/components/bc/input/BcInputText.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/frontend/components/notifications/management/NotificationsManagementDashboards.vue b/frontend/components/notifications/management/NotificationsManagementDashboards.vue index 00999cfa4..899c70043 100644 --- a/frontend/components/notifications/management/NotificationsManagementDashboards.vue +++ b/frontend/components/notifications/management/NotificationsManagementDashboards.vue @@ -9,6 +9,7 @@ import { getGroupLabel } from '~/utils/dashboard/group' import { type NotificationsManagementDashboardRow } from '~/types/notifications/management' import type { DashboardType } from '~/types/dashboard' import { useNotificationsManagementDashboards } from '~/composables/notifications/useNotificationsManagementDashboards' +import { NotificationsManagementModalWebhook } from '#components' const { t: $t } = useI18n() @@ -39,13 +40,23 @@ const wrappedDashboardGroups = computed(() => { } }) -const onEdit = (col: 'delete' | 'subscriptions' | 'webhook' | 'networks', row: NotificationsManagementDashboardRow) => { +type Dialog = 'delete' | 'subscriptions' | 'webhook' | 'networks' +const activeDialog = ref('') +const dialog = useDialog() + +const onEdit = (col: Dialog, row: NotificationsManagementDashboardRow) => { switch (col) { case 'subscriptions': alert('TODO: edit subscriptions' + row.group_id) break case 'webhook': - alert('TODO: edit webhook' + row.group_id) + activeDialog.value = col + dialog.open(NotificationsManagementModalWebhook, { + data: { + webhookUrl: row.webhook.url, + hasDiscord: row.webhook.via_discord, + }, + }) break case 'networks': alert('TODO: edit networks' + row.group_id) diff --git a/frontend/components/notifications/management/modal/NotificationsManagementModalWebhook.vue b/frontend/components/notifications/management/modal/NotificationsManagementModalWebhook.vue new file mode 100644 index 000000000..aa1ea32e0 --- /dev/null +++ b/frontend/components/notifications/management/modal/NotificationsManagementModalWebhook.vue @@ -0,0 +1,154 @@ + + + + + diff --git a/frontend/composables/useBcDialog.ts b/frontend/composables/useBcDialog.ts index b280f83db..61b603f39 100644 --- a/frontend/composables/useBcDialog.ts +++ b/frontend/composables/useBcDialog.ts @@ -63,5 +63,9 @@ export function useBcDialog (dialogProps?: DialogProps) { dialogRef.value.close() } } - return { props, dialogRef, setHeader } + + const close = () => { + dialogRef?.value?.close() + } + return { close, props, dialogRef, setHeader} } diff --git a/frontend/i18n/en.json b/frontend/i18n/en.json index 805c4c59a..e8a2d172f 100644 --- a/frontend/i18n/en.json +++ b/frontend/i18n/en.json @@ -342,8 +342,22 @@ "accounts": "Accounts ({count} Subscription) |Accounts ({count} Subscriptions)", "accounts_shortened": "Accounts ({count} Sub) |Accounts ({count} Subs)" } - } - + }, + "dialog": { + "button_webhook_test": "Send Test Notification", + "heading_webhook": "Edit Webhook", + "info_send_via_discord": "Enable this to receive notifications via Discord. Ensure you have a Discord webhook set up.", + "label_webhook_url": "Webhook URL", + "label_send_via_discord": "Send via Discord", + "placeholder_webhook": "https://webhook.example.com/id" + }, + "toast": { + "success": { + "test_webhook_url": "Webhook send successfully", + "test_discord": "Discord webhook send successfully" + }, + "error": "Webhook could not be sent successfully" + } } }, "dashboard": { @@ -919,6 +933,12 @@ "no_match": "The passwords don't match.", "not_new": "The new password must differ from the old one." }, - "tos_not_agreed": "Please accept the ToS & Privacy Policy." + "tos_not_agreed": "Please accept the ToS & Privacy Policy.", + "url": { + "invalid": "Please enter a valid URL." + }, + "webhook": { + "empty": "Please choose at least one webhook to test." + } } } diff --git a/frontend/types/customFetch.ts b/frontend/types/customFetch.ts index c16fc88af..4737f6a9e 100644 --- a/frontend/types/customFetch.ts +++ b/frontend/types/customFetch.ts @@ -45,7 +45,8 @@ export enum API_PATH { AVAILABLE_NETWORKS = '/availableNetworks', PRODUCT_SUMMARY = '/productSummary', STRIPE_CUSTOMER_PORTAL = '/stripe/customer-portal', - STRIPE_CHECKOUT_SESSION = '/stripe/checkout-session' + STRIPE_CHECKOUT_SESSION = '/stripe/checkout-session', + NOTIFICATIONS_TEST_WEBHOOK = '/users/me/notifications/test-webhook' } export type PathValues = Record