+
Total targeted observers {pushMessage?.receivers?.length ?? 0}
{pushMessage?.receivers?.map((receiver) => (
@@ -59,6 +57,13 @@ export default function PushMessageDetails(): FunctionComponent {
))}
+
diff --git a/web/src/features/monitoring-observers/components/PushMessageForm/PushMessageForm.tsx b/web/src/features/monitoring-observers/components/PushMessageForm/PushMessageForm.tsx
index dcf10ec67..14a6b0e8f 100644
--- a/web/src/features/monitoring-observers/components/PushMessageForm/PushMessageForm.tsx
+++ b/web/src/features/monitoring-observers/components/PushMessageForm/PushMessageForm.tsx
@@ -17,23 +17,23 @@ import { z } from 'zod';
import { authApi } from '@/common/auth-api';
import type { FunctionComponent } from '@/common/types';
import { PollingStationsFilters } from '@/components/PollingStationsFilters/PollingStationsFilters';
+import { RichTextEditor } from '@/components/rich-text-editor';
import { FilterBadge } from '@/components/ui/badge';
import { QueryParamsDataTable } from '@/components/ui/DataTable/QueryParamsDataTable';
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { toast } from '@/components/ui/use-toast';
+import { useCurrentElectionRoundStore } from '@/context/election-round.store';
import { Route } from '@/routes/monitoring-observers/create-new-message';
import { ChevronDownIcon } from '@heroicons/react/24/outline';
-import { useMutation } from '@tanstack/react-query';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useNavigate } from '@tanstack/react-router';
import { useDebounce } from '@uidotdev/usehooks';
import { useMonitoringObserversTags } from '../../../../hooks/tags-queries';
-import { useTargetedMonitoringObservers } from '../../hooks/push-messages-queries';
+import { pushMessagesKeys, useTargetedMonitoringObservers } from '../../hooks/push-messages-queries';
import { MonitoringObserverStatus } from '../../models/monitoring-observer';
import type { SendPushNotificationRequest } from '../../models/push-message';
import type { PushMessageTargetedObserversSearchParams } from '../../models/search-params';
import { targetedMonitoringObserverColDefs } from '../../utils/column-defs';
-import { useCurrentElectionRoundStore } from '@/context/election-round.store';
-import { Textarea } from '@/components/ui/textarea';
const createPushMessageSchema = z.object({
title: z.string().min(1, { message: 'Your message must have a title before sending.' }),
@@ -49,9 +49,11 @@ function PushMessageForm(): FunctionComponent {
const [totalRowsCount, setTotalRowsCount] = useState(0);
const [searchText, setSearchText] = useState
('');
const debouncedSearchText = useDebounce(searchText, 300);
- const currentElectionRoundId = useCurrentElectionRoundStore(s => s.currentElectionRoundId);
+ const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId);
const { data: tags } = useMonitoringObserversTags(currentElectionRoundId);
+ const queryClient = useQueryClient();
+
const onTagsFilterChange = useCallback(
(tag: string) => () => {
void navigate({
@@ -119,11 +121,15 @@ function PushMessageForm(): FunctionComponent {
});
const sendNotificationMutation = useMutation({
- mutationFn: ({ electionRoundId, request }: { electionRoundId: string, request: SendPushNotificationRequest }) => {
- return authApi.post(`/election-rounds/${electionRoundId}/notifications:send`, request);
+ mutationFn: ({ electionRoundId, request }: { electionRoundId: string; request: SendPushNotificationRequest }) => {
+ return authApi.post(
+ `/election-rounds/${electionRoundId}/notifications:send`,
+ request
+ );
},
onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: [pushMessagesKeys.all(currentElectionRoundId)] });
toast({
title: 'Success',
description: 'Notification sent',
@@ -140,7 +146,7 @@ function PushMessageForm(): FunctionComponent {
title: values.title,
body: values.messageBody,
...queryParams,
- }
+ },
});
}
@@ -182,8 +188,7 @@ function PushMessageForm(): FunctionComponent {
Message body *
- {/* */}
-
+
1000 characters
diff --git a/web/src/features/monitoring-observers/components/PushMessages/PushMessages.tsx b/web/src/features/monitoring-observers/components/PushMessages/PushMessages.tsx
index 0cc9372fc..f8697f7ac 100644
--- a/web/src/features/monitoring-observers/components/PushMessages/PushMessages.tsx
+++ b/web/src/features/monitoring-observers/components/PushMessages/PushMessages.tsx
@@ -50,12 +50,6 @@ function PushMessages(): FunctionComponent {
enableSorting: false,
enableGlobalFilter: false,
},
- {
- header: ({ column }) => ,
- accessorKey: 'body',
- enableSorting: false,
- enableGlobalFilter: false,
- },
{
header: '',
accessorKey: 'action',
diff --git a/web/tailwind.config.js b/web/tailwind.config.js
index f9e269b28..d27caf543 100644
--- a/web/tailwind.config.js
+++ b/web/tailwind.config.js
@@ -2,74 +2,74 @@ const colors = require('tailwindcss/colors');
/** @type {import('tailwindcss').Config} */
module.exports = {
- darkMode: ["class"],
- content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx,svg}"],
+ darkMode: ['class'],
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx,svg}'],
theme: {
container: {
center: true,
- padding: "2rem",
+ padding: '2rem',
screens: {
- "2xl": "1400px",
+ '2xl': '1400px',
},
},
extend: {
colors: {
- border: "hsl(var(--border))",
- input: "hsl(var(--input))",
- ring: "hsl(var(--ring))",
- background: "hsl(var(--background))",
- foreground: "hsl(var(--foreground))",
+ border: 'hsl(var(--border))',
+ input: 'hsl(var(--input))',
+ ring: 'hsl(var(--ring))',
+ background: 'hsl(var(--background))',
+ foreground: 'hsl(var(--foreground))',
primary: {
...colors.violet,
- DEFAULT: "hsl(var(--primary))",
- foreground: "hsl(var(--primary-foreground))",
+ DEFAULT: 'hsl(var(--primary))',
+ foreground: 'hsl(var(--primary-foreground))',
},
secondary: {
...colors.yellow,
- DEFAULT: "hsl(var(--secondary))",
- foreground: "hsl(var(--secondary-foreground))",
+ DEFAULT: 'hsl(var(--secondary))',
+ foreground: 'hsl(var(--secondary-foreground))',
},
destructive: {
- DEFAULT: "hsl(var(--destructive))",
- foreground: "hsl(var(--destructive-foreground))",
+ DEFAULT: 'hsl(var(--destructive))',
+ foreground: 'hsl(var(--destructive-foreground))',
},
muted: {
- DEFAULT: "hsl(var(--muted))",
- foreground: "hsl(var(--muted-foreground))",
+ DEFAULT: 'hsl(var(--muted))',
+ foreground: 'hsl(var(--muted-foreground))',
},
accent: {
- DEFAULT: "hsl(var(--accent))",
- foreground: "hsl(var(--accent-foreground))",
+ DEFAULT: 'hsl(var(--accent))',
+ foreground: 'hsl(var(--accent-foreground))',
},
popover: {
- DEFAULT: "hsl(var(--popover))",
- foreground: "hsl(var(--popover-foreground))",
+ DEFAULT: 'hsl(var(--popover))',
+ foreground: 'hsl(var(--popover-foreground))',
},
card: {
- DEFAULT: "hsl(var(--card))",
- foreground: "hsl(var(--card-foreground))",
+ DEFAULT: 'hsl(var(--card))',
+ foreground: 'hsl(var(--card-foreground))',
},
},
borderRadius: {
lg: `var(--radius)`,
md: `calc(var(--radius) - 2px)`,
- sm: "calc(var(--radius) - 4px)",
+ sm: 'calc(var(--radius) - 4px)',
},
keyframes: {
- "accordion-down": {
+ 'accordion-down': {
from: { height: 0 },
- to: { height: "var(--radix-accordion-content-height)" },
+ to: { height: 'var(--radix-accordion-content-height)' },
},
- "accordion-up": {
- from: { height: "var(--radix-accordion-content-height)" },
+ 'accordion-up': {
+ from: { height: 'var(--radix-accordion-content-height)' },
to: { height: 0 },
},
},
animation: {
- "accordion-down": "accordion-down 0.2s ease-out",
- "accordion-up": "accordion-up 0.2s ease-out",
+ 'accordion-down': 'accordion-down 0.2s ease-out',
+ 'accordion-up': 'accordion-up 0.2s ease-out',
},
},
},
- plugins: [require("tailwindcss-animate"), ],
-}
+ plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')],
+};