From f56c0186716a33b54114b9ee26399b210bd949ec Mon Sep 17 00:00:00 2001 From: Ion Dormenco Date: Sat, 23 Nov 2024 14:36:36 +0200 Subject: [PATCH] add readonly view --- ...enReportingNgoAdminAuthorizationHandler.cs | 5 +- ...gNgoAdminOrObserverAuthorizationHandler.cs | 5 +- .../CoalitionsFeatureInstaller.cs | 3 - api/src/Feature.Coalitions/Delete/Endpoint.cs | 20 +--- .../Feature.Coalitions/FormAccess/Endpoint.cs | 18 ---- .../Services/FormSubmissionsCleanupService.cs | 99 ------------------- .../IFormSubmissionsCleanupService.cs | 23 ----- api/src/Feature.Coalitions/Update/Endpoint.cs | 20 +--- .../MonitoringObserverModel.cs | 3 +- .../Feature.ObserverGuide/List/Endpoint.cs | 3 +- ...dminOrObserverAuthorizationHandlerTests.cs | 4 +- .../components/dialogs/CreateDialog/index.tsx | 8 +- .../CitizenNotificationMessageForm.tsx | 7 +- .../CitizenNotificationsDashboard.tsx | 8 +- .../components/Guides/GuidesDashboard.tsx | 5 +- .../forms/components/Dashboard/Dashboard.tsx | 70 +++++++++---- .../MonitoringObserverDetailsView.tsx | 10 +- .../MonitoringObserversList.tsx | 31 ++++-- .../components/PushMessages/PushMessages.tsx | 11 ++- .../CitizenReportDetails.tsx | 11 ++- .../FormSubmissionDetails.tsx | 15 +-- .../IncidentReportDetails.tsx | 7 +- .../QuickReportDetails/QuickReportDetails.tsx | 7 +- 23 files changed, 150 insertions(+), 243 deletions(-) delete mode 100644 api/src/Feature.Coalitions/Services/FormSubmissionsCleanupService.cs delete mode 100644 api/src/Feature.Coalitions/Services/IFormSubmissionsCleanupService.cs diff --git a/api/src/Authorization.Policies/RequirementHandlers/CitizenReportingNgoAdminAuthorizationHandler.cs b/api/src/Authorization.Policies/RequirementHandlers/CitizenReportingNgoAdminAuthorizationHandler.cs index 8171bf3b1..e242a1376 100644 --- a/api/src/Authorization.Policies/RequirementHandlers/CitizenReportingNgoAdminAuthorizationHandler.cs +++ b/api/src/Authorization.Policies/RequirementHandlers/CitizenReportingNgoAdminAuthorizationHandler.cs @@ -36,8 +36,7 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext return; } - if (result.ElectionRoundStatus == ElectionRoundStatus.Archived - || result.NgoStatus == NgoStatus.Deactivated + if (result.NgoStatus == NgoStatus.Deactivated || result.MonitoringNgoStatus == MonitoringNgoStatus.Suspended) { context.Fail(); @@ -46,4 +45,4 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context.Succeed(requirement); } -} \ No newline at end of file +} diff --git a/api/src/Authorization.Policies/RequirementHandlers/MonitoringNgoAdminOrObserverAuthorizationHandler.cs b/api/src/Authorization.Policies/RequirementHandlers/MonitoringNgoAdminOrObserverAuthorizationHandler.cs index 4dea606cf..4d5e09c7f 100644 --- a/api/src/Authorization.Policies/RequirementHandlers/MonitoringNgoAdminOrObserverAuthorizationHandler.cs +++ b/api/src/Authorization.Policies/RequirementHandlers/MonitoringNgoAdminOrObserverAuthorizationHandler.cs @@ -51,8 +51,7 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext if (ngoAdminResult is not null) { - if (ngoAdminResult.ElectionRoundStatus == ElectionRoundStatus.Archived || - ngoAdminResult.NgoStatus == NgoStatus.Deactivated || + if (ngoAdminResult.NgoStatus == NgoStatus.Deactivated || ngoAdminResult.MonitoringNgoStatus == MonitoringNgoStatus.Suspended) { context.Fail(); @@ -66,4 +65,4 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context.Fail(); } -} \ No newline at end of file +} diff --git a/api/src/Feature.Coalitions/CoalitionsFeatureInstaller.cs b/api/src/Feature.Coalitions/CoalitionsFeatureInstaller.cs index d13a7a281..10dff27e7 100644 --- a/api/src/Feature.Coalitions/CoalitionsFeatureInstaller.cs +++ b/api/src/Feature.Coalitions/CoalitionsFeatureInstaller.cs @@ -1,6 +1,5 @@ using Dapper; using Feature.NgoCoalitions.Models; -using Feature.NgoCoalitions.Services; using Microsoft.Extensions.DependencyInjection; using Vote.Monitor.Core.Converters; @@ -12,8 +11,6 @@ public static IServiceCollection AddCoalitionsFeature(this IServiceCollection se { SqlMapper.AddTypeHandler(typeof(CoalitionMember[]), new JsonToObjectConverter()); - services.AddScoped(); - return services; } } diff --git a/api/src/Feature.Coalitions/Delete/Endpoint.cs b/api/src/Feature.Coalitions/Delete/Endpoint.cs index b50eebafe..06c3b3de6 100644 --- a/api/src/Feature.Coalitions/Delete/Endpoint.cs +++ b/api/src/Feature.Coalitions/Delete/Endpoint.cs @@ -1,8 +1,6 @@ -using Feature.NgoCoalitions.Services; +namespace Feature.NgoCoalitions.Delete; -namespace Feature.NgoCoalitions.Delete; - -public class Endpoint(VoteMonitorContext context, IFormSubmissionsCleanupService cleanupService) +public class Endpoint(VoteMonitorContext context) : Endpoint> { public override void Configure() @@ -25,20 +23,6 @@ public override async Task> ExecuteAsync( return TypedResults.NotFound(); } - // members data should be purged but coalition leader keeps their data - var membersToRemove = coalition - .Memberships - .Where(x => x.MonitoringNgoId != coalition.LeaderId) - .Select(x => x.MonitoringNgoId) - .ToList(); - - // Delete orphaned data - if (membersToRemove.Any()) - { - await Task.WhenAll(membersToRemove.Select(monitoringNgoId => - cleanupService.CleanupFormSubmissionsAsync(req.ElectionRoundId, req.CoalitionId, monitoringNgoId))); - } - context.Coalitions.Remove(coalition); await context.SaveChangesAsync(ct); diff --git a/api/src/Feature.Coalitions/FormAccess/Endpoint.cs b/api/src/Feature.Coalitions/FormAccess/Endpoint.cs index ac9c24430..777ce2802 100644 --- a/api/src/Feature.Coalitions/FormAccess/Endpoint.cs +++ b/api/src/Feature.Coalitions/FormAccess/Endpoint.cs @@ -1,5 +1,4 @@ using Authorization.Policies.Requirements; -using Feature.NgoCoalitions.Services; using Microsoft.AspNetCore.Authorization; using Vote.Monitor.Domain.Entities.CoalitionAggregate; @@ -7,7 +6,6 @@ namespace Feature.NgoCoalitions.FormAccess; public class Endpoint( VoteMonitorContext context, - IFormSubmissionsCleanupService cleanupService, IAuthorizationService authorizationService) : Endpoint> { @@ -69,26 +67,10 @@ public override async Task> Execute .Select(x => x.Id) .ToListAsync(ct); - var ngosWithRevokedAccess = - coalition.FormAccess - .Where(x => !coalitionMonitoringNgoIds.Contains(x.MonitoringNgoId)) - .ToList(); - var ngosGainedFormAccess = coalitionMonitoringNgoIds.Where(x => coalition.FormAccess.All(fa => fa.MonitoringNgoId != x)) .Select(id => CoalitionFormAccess.Create(coalition.Id, id, req.FormId)) .ToList(); - - if (ngosWithRevokedAccess.Any()) - { - context.CoalitionFormAccess.RemoveRange(ngosWithRevokedAccess); - - foreach (var memberId in ngosWithRevokedAccess) - { - await cleanupService.CleanupFormSubmissionsAsync( - req.ElectionRoundId, req.CoalitionId, memberId.MonitoringNgoId, form.Id); - } - } if (ngosGainedFormAccess.Any()) { diff --git a/api/src/Feature.Coalitions/Services/FormSubmissionsCleanupService.cs b/api/src/Feature.Coalitions/Services/FormSubmissionsCleanupService.cs deleted file mode 100644 index 57a879840..000000000 --- a/api/src/Feature.Coalitions/Services/FormSubmissionsCleanupService.cs +++ /dev/null @@ -1,99 +0,0 @@ -namespace Feature.NgoCoalitions.Services; - -public class FormSubmissionsCleanupService(VoteMonitorContext context) : IFormSubmissionsCleanupService -{ - public async Task CleanupFormSubmissionsAsync(Guid electionRoundId, Guid coalitionId, Guid monitoringNgoId) - { - var formIds = await context.CoalitionFormAccess.Where(x => - x.CoalitionId == coalitionId && x.Coalition.ElectionRoundId == electionRoundId) - .Select(x => x.FormId) - .Distinct() - .ToListAsync(); - - await context - .FormSubmissions - .Where(x => x.ElectionRoundId == electionRoundId) - .Where(x => monitoringNgoId == x.MonitoringObserver.MonitoringNgoId) - .Where(x => formIds.Contains(x.FormId)) - .ExecuteDeleteAsync(); - - await context - .Attachments - .Where(x => monitoringNgoId == x.MonitoringObserver.MonitoringNgoId && formIds.Contains(x.FormId)) - .ExecuteDeleteAsync(); - - await context - .Notes - .Where(x => x.ElectionRoundId == electionRoundId) - .Where(x => monitoringNgoId == x.MonitoringObserver.MonitoringNgoId) - .Where(x => formIds.Contains(x.FormId)) - .ExecuteDeleteAsync(); - - await context - .IncidentReports - .Where(x => x.ElectionRoundId == electionRoundId) - .Where(x => monitoringNgoId == x.MonitoringObserver.MonitoringNgoId) - .Where(x => formIds.Contains(x.FormId)) - .ExecuteDeleteAsync(); - - await context - .IncidentReportAttachments - .Where(x => x.ElectionRoundId == electionRoundId) - .Where(x => monitoringNgoId == x.IncidentReport.MonitoringObserver.MonitoringNgoId) - .Where(x => formIds.Contains(x.FormId)) - .ExecuteDeleteAsync(); - } - - public async Task CleanupFormSubmissionsAsync(Guid electionRoundId, Guid coalitionId, Guid monitoringNgoId, - Guid formId) - { - if (!await context.CoalitionFormAccess.AnyAsync(x => - x.Form.ElectionRoundId == electionRoundId - && x.FormId == formId - && x.CoalitionId == coalitionId - && x.Coalition.ElectionRoundId == electionRoundId)) - { - return; - } - - await context - .FormSubmissions - .Where(x => x.ElectionRoundId == electionRoundId) - .Where(x => monitoringNgoId == x.MonitoringObserver.MonitoringNgoId) - .Where(x => x.FormId == formId) - .Where(x => x.Form.ElectionRoundId == electionRoundId) - .ExecuteDeleteAsync(); - - await context - .Attachments - .Where(x => x.ElectionRoundId == electionRoundId) - .Where(x => monitoringNgoId == x.MonitoringObserver.MonitoringNgoId) - .Where(x => x.FormId == formId) - .Where(x => x.Form.ElectionRoundId == electionRoundId) - .ExecuteDeleteAsync(); - - await context - .Notes - .Where(x => x.ElectionRoundId == electionRoundId) - .Where(x => monitoringNgoId == x.MonitoringObserver.MonitoringNgoId) - .Where(x => x.FormId == formId) - .Where(x => x.Form.ElectionRoundId == electionRoundId) - .ExecuteDeleteAsync(); - - await context - .IncidentReports - .Where(x => x.ElectionRoundId == electionRoundId) - .Where(x => monitoringNgoId == x.MonitoringObserver.MonitoringNgoId) - .Where(x => x.Form.ElectionRoundId == electionRoundId) - .Where(x => x.FormId == formId) - .ExecuteDeleteAsync(); - - await context - .IncidentReportAttachments - .Where(x => x.ElectionRoundId == electionRoundId) - .Where(x => monitoringNgoId == x.IncidentReport.MonitoringObserver.MonitoringNgoId) - .Where(x => x.FormId == formId) - .Where(x => x.Form.ElectionRoundId == electionRoundId) - .ExecuteDeleteAsync(); - } -} diff --git a/api/src/Feature.Coalitions/Services/IFormSubmissionsCleanupService.cs b/api/src/Feature.Coalitions/Services/IFormSubmissionsCleanupService.cs deleted file mode 100644 index 26e856d5c..000000000 --- a/api/src/Feature.Coalitions/Services/IFormSubmissionsCleanupService.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Feature.NgoCoalitions.Services; - -public interface IFormSubmissionsCleanupService -{ - /// - /// Removes all data submitted by a ngo ,ex member of the coalition - /// - /// - /// - /// - /// - Task CleanupFormSubmissionsAsync(Guid electionRoundId, Guid coalitionId, Guid monitoringNgoId); - - /// - /// Removes all data submitted by a ngo for a form when form access is revoked - /// - /// - /// - /// - /// - /// - Task CleanupFormSubmissionsAsync(Guid electionRoundId, Guid coalitionId, Guid monitoringNgoId, Guid formId); -} diff --git a/api/src/Feature.Coalitions/Update/Endpoint.cs b/api/src/Feature.Coalitions/Update/Endpoint.cs index 8e7324083..fa46d47c7 100644 --- a/api/src/Feature.Coalitions/Update/Endpoint.cs +++ b/api/src/Feature.Coalitions/Update/Endpoint.cs @@ -1,10 +1,9 @@ using Feature.NgoCoalitions.Models; -using Feature.NgoCoalitions.Services; using Vote.Monitor.Domain.Entities.CoalitionAggregate; namespace Feature.NgoCoalitions.Update; -public class Endpoint(VoteMonitorContext context, IFormSubmissionsCleanupService cleanupService) +public class Endpoint(VoteMonitorContext context) : Endpoint, NotFound, ProblemDetails>> { public override void Configure() @@ -49,26 +48,9 @@ public override async Task, NotFound, ProblemDetails> context.MonitoringNgos.Add(monitoringNgo); } - var oldMembers = coalition.Memberships; - coalition.Update(req.CoalitionName, coalitionMembers.Select(x => CoalitionMembership.Create(req.ElectionRoundId, req.CoalitionId, x.Id))); - var removedMembers = oldMembers - .Where(cm=>cm.MonitoringNgo.Id != coalition.LeaderId) - .Where(cm => coalitionMembers.All(x => x.Id != cm.MonitoringNgo.Id)) - .Select(x => x.MonitoringNgo.Id) - .ToList(); - - // Delete orphaned data - if (removedMembers.Any()) - { - foreach (var memberId in removedMembers) - { - await cleanupService.CleanupFormSubmissionsAsync(req.ElectionRoundId, req.CoalitionId, memberId); - } - } - await context.SaveChangesAsync(ct); return TypedResults.Ok(CoalitionModel.FromEntity(coalition)); } diff --git a/api/src/Feature.MonitoringObservers/MonitoringObserverModel.cs b/api/src/Feature.MonitoringObservers/MonitoringObserverModel.cs index 6d7aabc74..62aab18d3 100644 --- a/api/src/Feature.MonitoringObservers/MonitoringObserverModel.cs +++ b/api/src/Feature.MonitoringObservers/MonitoringObserverModel.cs @@ -11,8 +11,7 @@ public class MonitoringObserverModel public string Email { get; init; } public string PhoneNumber { get; init; } public string[] Tags { get; init; } + public bool IsOwnObserver { get; init; } public DateTime? LatestActivityAt { get; init; } public MonitoringObserverStatus Status { get; init; } } - - diff --git a/api/src/Feature.ObserverGuide/List/Endpoint.cs b/api/src/Feature.ObserverGuide/List/Endpoint.cs index c655b5e15..7d15ab068 100644 --- a/api/src/Feature.ObserverGuide/List/Endpoint.cs +++ b/api/src/Feature.ObserverGuide/List/Endpoint.cs @@ -35,8 +35,7 @@ await authorizationService.AuthorizeAsync(User, var isNgoAdmin = currentUserRoleProvider.IsNgoAdmin(); var isObserver = currentUserRoleProvider.IsObserver(); - - + var observerId = currentUserProvider.GetUserId(); var ngoId = currentUserProvider.GetNgoId(); diff --git a/api/tests/Authorization.Policies.UnitTests/RequirementsHandlers/MonitoringNgoAdminOrObserverAuthorizationHandlerTests.cs b/api/tests/Authorization.Policies.UnitTests/RequirementsHandlers/MonitoringNgoAdminOrObserverAuthorizationHandlerTests.cs index e0ba11fb6..8ee90fda9 100644 --- a/api/tests/Authorization.Policies.UnitTests/RequirementsHandlers/MonitoringNgoAdminOrObserverAuthorizationHandlerTests.cs +++ b/api/tests/Authorization.Policies.UnitTests/RequirementsHandlers/MonitoringNgoAdminOrObserverAuthorizationHandlerTests.cs @@ -62,7 +62,7 @@ public async Task HandleRequirementAsync_MonitoringNgoNotFound_Failure() } [Fact] - public async Task HandleRequirementAsync_ElectionRoundArchived_Failure() + public async Task HandleRequirementAsync_ElectionRoundArchived_Success() { // Arrange _currentUserRoleProvider.IsNgoAdmin().Returns(true); @@ -78,7 +78,7 @@ public async Task HandleRequirementAsync_ElectionRoundArchived_Failure() await _handler.HandleAsync(_context); // Assert - _context.HasSucceeded.Should().BeFalse(); + _context.HasSucceeded.Should().BeTrue(); } [Fact] diff --git a/web/src/components/dialogs/CreateDialog/index.tsx b/web/src/components/dialogs/CreateDialog/index.tsx index b815b8b4c..f5ace9565 100644 --- a/web/src/components/dialogs/CreateDialog/index.tsx +++ b/web/src/components/dialogs/CreateDialog/index.tsx @@ -12,6 +12,9 @@ import { DialogTrigger, } from '@/components/ui/dialog'; import { useTranslation } from "react-i18next"; +import { useCurrentElectionRoundStore } from "@/context/election-round.store"; +import { useElectionRoundDetails } from "@/features/election-event/hooks/election-event-hooks"; +import { ElectionRoundStatus } from "@/common/types"; interface Props { title?: ReactNode; @@ -20,10 +23,13 @@ interface Props { } const CreateDialog = ({ title, description, children }: Props): ReactNode => { + const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId); + const { data: electionRound } = useElectionRoundDetails(currentElectionRoundId); + return ( - diff --git a/web/src/features/CitizenNotifications/CitizenNotificationMessageForm/CitizenNotificationMessageForm.tsx b/web/src/features/CitizenNotifications/CitizenNotificationMessageForm/CitizenNotificationMessageForm.tsx index 75705a16a..4334fdc94 100644 --- a/web/src/features/CitizenNotifications/CitizenNotificationMessageForm/CitizenNotificationMessageForm.tsx +++ b/web/src/features/CitizenNotifications/CitizenNotificationMessageForm/CitizenNotificationMessageForm.tsx @@ -7,7 +7,7 @@ import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { authApi } from '@/common/auth-api'; -import type { FunctionComponent } from '@/common/types'; +import { ElectionRoundStatus, type FunctionComponent } from '@/common/types'; import { RichTextEditor } from '@/components/rich-text-editor'; import { toast } from '@/components/ui/use-toast'; import { useCurrentElectionRoundStore } from '@/context/election-round.store'; @@ -15,6 +15,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useNavigate, useRouter } from '@tanstack/react-router'; import { citizenNotificationsKeys } from '../hooks/citizen-notifications-queries'; import { Button } from '@/components/ui/button'; +import { useElectionRoundDetails } from '@/features/election-event/hooks/election-event-hooks'; const createPushMessageSchema = z.object({ title: z.string().min(1, { message: 'Your message must have a title before sending.' }), @@ -27,6 +28,8 @@ const createPushMessageSchema = z.object({ function CitizenNotificationMessageForm(): FunctionComponent { const navigate = useNavigate(); const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId); + const { data: electionRound } = useElectionRoundDetails(currentElectionRoundId); + const router = useRouter(); const queryClient = useQueryClient(); @@ -113,7 +116,7 @@ function CitizenNotificationMessageForm(): FunctionComponent { />
- +
diff --git a/web/src/features/CitizenNotifications/CitizenNotificationsDashboard/CitizenNotificationsDashboard.tsx b/web/src/features/CitizenNotifications/CitizenNotificationsDashboard/CitizenNotificationsDashboard.tsx index 4116400c2..fad103b65 100644 --- a/web/src/features/CitizenNotifications/CitizenNotificationsDashboard/CitizenNotificationsDashboard.tsx +++ b/web/src/features/CitizenNotifications/CitizenNotificationsDashboard/CitizenNotificationsDashboard.tsx @@ -9,13 +9,14 @@ import type { CellContext, ColumnDef } from '@tanstack/react-table'; import { Plus } from 'lucide-react'; import { DateTimeFormat } from '@/common/formats'; -import type { FunctionComponent } from '@/common/types'; +import { ElectionRoundStatus, type FunctionComponent } from '@/common/types'; import type { TableCellProps } from '@/components/ui/DataTable/DataTable'; import { useCurrentElectionRoundStore } from '@/context/election-round.store'; import { format } from 'date-fns'; import { useCallback } from 'react'; import { useCitizenNotifications } from '../hooks/citizen-notifications-queries'; import { CitizenNotificationModel } from '../models/citizen-notification'; +import { useElectionRoundDetails } from '@/features/election-event/hooks/election-event-hooks'; function CitizenNotificationsDashboard(): FunctionComponent { const pushMessagesColDefs: ColumnDef[] = [ @@ -68,6 +69,7 @@ function CitizenNotificationsDashboard(): FunctionComponent { const navigate = useNavigate(); const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId); + const { data: electionRound } = useElectionRoundDetails(currentElectionRoundId); const navigateToPushMessage = useCallback( (notificationId: string) => { @@ -82,8 +84,8 @@ function CitizenNotificationsDashboard(): FunctionComponent {
Push messages
- - diff --git a/web/src/features/election-event/components/Guides/GuidesDashboard.tsx b/web/src/features/election-event/components/Guides/GuidesDashboard.tsx index bca4a45b1..70ce1478b 100644 --- a/web/src/features/election-event/components/Guides/GuidesDashboard.tsx +++ b/web/src/features/election-event/components/Guides/GuidesDashboard.tsx @@ -30,6 +30,8 @@ import { observerGuidesKeys, useObserverGuides } from '../../hooks/observer-guid import { GuideModel, GuidePageType, GuideType } from '../../models/guide'; import AddGuideDialog from './AddGuideDialog'; import EditGuideDialog from './EditGuideDialog'; +import { useElectionRoundDetails } from '../../hooks/election-event-hooks'; +import { ElectionRoundStatus } from '@/common/types'; export interface GuidesDashboardProps { guidePageType: GuidePageType; @@ -45,6 +47,7 @@ export default function GuidesDashboard({ guidePageType }: GuidesDashboardProps) const [newGuideType, setNewGuideType] = useState(undefined); const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId); + const { data: electionRound } = useElectionRoundDetails(currentElectionRoundId); async function handleDeleteGuide(guideId: string, guideName: string): Promise { if ( @@ -222,7 +225,7 @@ export default function GuidesDashboard({ guidePageType }: GuidesDashboardProps) : i18n.t('electionEvent.guides.citizenGuidesCardTitle')} - + diff --git a/web/src/features/monitoring-observers/components/MonitoringObserversList/MonitoringObserversList.tsx b/web/src/features/monitoring-observers/components/MonitoringObserversList/MonitoringObserversList.tsx index 913f16ae9..5812ae1a0 100644 --- a/web/src/features/monitoring-observers/components/MonitoringObserversList/MonitoringObserversList.tsx +++ b/web/src/features/monitoring-observers/components/MonitoringObserversList/MonitoringObserversList.tsx @@ -39,32 +39,35 @@ import ImportMonitoringObserversDialog from '../MonitoringObserversList/ImportMo import ImportMonitoringObserversErrorsDialog from '../MonitoringObserversList/ImportMonitoringObserversErrorsDialog'; import ConfirmResendInvitationDialog from './ConfirmResendInvitationDialog'; import CreateMonitoringObserverDialog from './CreateMonitoringObserverDialog'; +import { useElectionRoundDetails } from '@/features/election-event/hooks/election-event-hooks'; +import { ElectionRoundStatus } from '@/common/types'; function MonitoringObserversList() { const navigate = useNavigate(); const router = useRouter(); const search = Route.useSearch(); const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId); + const { data: electionRound } = useElectionRoundDetails(currentElectionRoundId); const monitoringObserverColDefs: ColumnDef[] = useMemo(() => { return [ { id: 'displayName', header: ({ column }) => , - accessorFn: (row)=> row.displayName, + accessorFn: (row) => row.displayName, enableSorting: true, enableGlobalFilter: true, }, { id: 'email', header: ({ column }) => , - accessorFn: (row)=> row.email, + accessorFn: (row) => row.email, enableSorting: true, }, { id: 'tags', header: ({ column }) => , - accessorFn: (row)=> row.tags, + accessorFn: (row) => row.tags, cell: ({ row: { original: { tags }, @@ -74,13 +77,13 @@ function MonitoringObserversList() { { id: 'phoneNumber', header: ({ column }) => , - accessorFn: (row)=> row.phoneNumber, + accessorFn: (row) => row.phoneNumber, enableSorting: true, }, { id: 'status', header: ({ column }) => , - accessorFn: (row)=> row.status, + accessorFn: (row) => row.status, enableSorting: true, cell: ({ row: { @@ -91,7 +94,7 @@ function MonitoringObserversList() { { id: 'latestActivityAt', header: ({ column }) => , - accessorFn: (row)=> row.latestActivityAt, + accessorFn: (row) => row.latestActivityAt, enableSorting: true, cell: ({ row: { @@ -110,9 +113,16 @@ function MonitoringObserversList() { navigateToObserver(row.original.id)}>View - navigateToEdit(row.original.id)}>Edit navigateToEdit(row.original.id)}> + Edit + + handleResendInviteToObserver(row.original.id)}> Resend invitation email @@ -269,6 +279,7 @@ function MonitoringObserversList() { /> - @@ -312,7 +323,7 @@ function MonitoringObserversList() { Export monitoring observer list - diff --git a/web/src/features/monitoring-observers/components/PushMessages/PushMessages.tsx b/web/src/features/monitoring-observers/components/PushMessages/PushMessages.tsx index d4cb54879..e82a8d1bb 100644 --- a/web/src/features/monitoring-observers/components/PushMessages/PushMessages.tsx +++ b/web/src/features/monitoring-observers/components/PushMessages/PushMessages.tsx @@ -9,13 +9,14 @@ import type { CellContext, ColumnDef } from '@tanstack/react-table'; import { Plus } from 'lucide-react'; import { DateTimeFormat } from '@/common/formats'; -import type { FunctionComponent } from '@/common/types'; +import { ElectionRoundStatus, type FunctionComponent } from '@/common/types'; import type { TableCellProps } from '@/components/ui/DataTable/DataTable'; import { useCurrentElectionRoundStore } from '@/context/election-round.store'; import { format } from 'date-fns'; import { useCallback } from 'react'; import { usePushMessages } from '../../hooks/push-messages-queries'; import type { PushMessageModel } from '../../models/push-message'; +import { useElectionRoundDetails } from '@/features/election-event/hooks/election-event-hooks'; function PushMessages(): FunctionComponent { const pushMessagesColDefs: ColumnDef[] = [ @@ -77,6 +78,7 @@ function PushMessages(): FunctionComponent { const navigate = useNavigate(); const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId); + const { data: electionRound } = useElectionRoundDetails(currentElectionRoundId); const navigateToPushMessage = useCallback( (id: string) => { @@ -91,8 +93,11 @@ function PushMessages(): FunctionComponent {
Push messages
- - diff --git a/web/src/features/responses/components/CitizenReportDetails/CitizenReportDetails.tsx b/web/src/features/responses/components/CitizenReportDetails/CitizenReportDetails.tsx index 006dd1e22..da33a78bb 100644 --- a/web/src/features/responses/components/CitizenReportDetails/CitizenReportDetails.tsx +++ b/web/src/features/responses/components/CitizenReportDetails/CitizenReportDetails.tsx @@ -1,5 +1,10 @@ import { authApi } from '@/common/auth-api'; -import { CitizenReportFollowUpStatus, FormSubmissionFollowUpStatus, type FunctionComponent } from '@/common/types'; +import { + CitizenReportFollowUpStatus, + ElectionRoundStatus, + FormSubmissionFollowUpStatus, + type FunctionComponent, +} from '@/common/types'; import Layout from '@/components/layout/Layout'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; @@ -18,10 +23,13 @@ import { usePrevSearch } from '@/common/prev-search-store'; import { NavigateBack } from '@/components/NavigateBack/NavigateBack'; import { DateTimeFormat } from '@/common/formats'; import { format } from 'date-fns'; +import { useElectionRoundDetails } from '@/features/election-event/hooks/election-event-hooks'; export default function CitizenReportDetails(): FunctionComponent { const { citizenReportId } = Route.useParams(); const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId); + const { data: electionRound } = useElectionRoundDetails(currentElectionRoundId); + const { data: citizenReport } = useSuspenseQuery( citizenReportDetailsQueryOptions(currentElectionRoundId, citizenReportId) ); @@ -122,6 +130,7 @@ export default function CitizenReportDetails(): FunctionComponent {