From 2d476d4569618a5c65a7f23ed7c16f3c7fb0cb36 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 10 Dec 2024 04:19:09 +0000 Subject: [PATCH] Refactor sider to remove deprecated jsx-style menu items --- packages/portal/graphql/graphql-env.d.ts | 7 +- packages/portal/package.json | 2 +- .../portal/src/config/refine/authorization.ts | 65 ++-- .../src/elements/components/sider/index.tsx | 359 ++++++++---------- packages/portal/src/routes/__root.tsx | 29 +- yarn.lock | 111 +++++- 6 files changed, 322 insertions(+), 251 deletions(-) diff --git a/packages/portal/graphql/graphql-env.d.ts b/packages/portal/graphql/graphql-env.d.ts index 6a5b9fb8..1d149818 100644 --- a/packages/portal/graphql/graphql-env.d.ts +++ b/packages/portal/graphql/graphql-env.d.ts @@ -2,10 +2,10 @@ /* prettier-ignore */ export type introspection_types = { - 'AbstractGraphQLPaginatedResponse': { kind: 'INTERFACE'; name: 'AbstractGraphQLPaginatedResponse'; fields: { 'page': { name: 'page'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'PositiveInt'; ofType: null; }; } }; 'pageSize': { name: 'pageSize'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; 'total': { name: 'total'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; }; possibleTypes: 'ListDailyDepartmentNotificationsResponse' | 'ListDevicesResponse' | 'ListEventsResponse' | 'ListFundraisingEntriesResponse' | 'ListImagesResponse' | 'ListMarathonHoursResponse' | 'ListMarathonsResponse' | 'ListNotificationDeliveriesResponse' | 'ListNotificationsResponse' | 'ListPeopleResponse' | 'ListPointEntriesResponse' | 'ListPointOpportunitiesResponse' | 'ListSolicitationCodesResponse' | 'ListTeamsResponse'; }; + 'AbstractGraphQLPaginatedResponse': { kind: 'INTERFACE'; name: 'AbstractGraphQLPaginatedResponse'; fields: { 'page': { name: 'page'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'PositiveInt'; ofType: null; }; } }; 'pageSize': { name: 'pageSize'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; 'total': { name: 'total'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; }; possibleTypes: 'ListAuditLogsResponse' | 'ListDailyDepartmentNotificationsResponse' | 'ListDevicesResponse' | 'ListEventsResponse' | 'ListFundraisingEntriesResponse' | 'ListImagesResponse' | 'ListMarathonHoursResponse' | 'ListMarathonsResponse' | 'ListNotificationDeliveriesResponse' | 'ListNotificationsResponse' | 'ListPeopleResponse' | 'ListPointEntriesResponse' | 'ListPointOpportunitiesResponse' | 'ListSolicitationCodesResponse' | 'ListTeamsResponse'; }; 'AccessLevel': { name: 'AccessLevel'; enumValues: 'Admin' | 'Committee' | 'CommitteeChairOrCoordinator' | 'None' | 'Public' | 'SuperAdmin' | 'UKY'; }; 'AssignEntryToPersonInput': { kind: 'INPUT_OBJECT'; name: 'AssignEntryToPersonInput'; isOneOf: false; inputFields: [{ name: 'amount'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Float'; ofType: null; }; }; defaultValue: null }]; }; - 'AuditLogNode': { kind: 'OBJECT'; name: 'AuditLogNode'; fields: { 'createdAt': { name: 'createdAt'; type: { kind: 'SCALAR'; name: 'DateTimeISO'; ofType: null; } }; 'details': { name: 'details'; type: { kind: 'SCALAR'; name: 'JSONObject'; ofType: null; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'GlobalId'; ofType: null; }; } }; 'subject': { name: 'subject'; type: { kind: 'INTERFACE'; name: 'Node'; ofType: null; } }; 'subjectJson': { name: 'subjectJson'; type: { kind: 'SCALAR'; name: 'JSONObject'; ofType: null; } }; 'summary': { name: 'summary'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'updatedAt': { name: 'updatedAt'; type: { kind: 'SCALAR'; name: 'DateTimeISO'; ofType: null; } }; 'user': { name: 'user'; type: { kind: 'OBJECT'; name: 'PersonNode'; ofType: null; } }; }; }; + 'AuditLogNode': { kind: 'OBJECT'; name: 'AuditLogNode'; fields: { 'createdAt': { name: 'createdAt'; type: { kind: 'SCALAR'; name: 'DateTimeISO'; ofType: null; } }; 'details': { name: 'details'; type: { kind: 'SCALAR'; name: 'JSONObject'; ofType: null; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'GlobalId'; ofType: null; }; } }; 'subject': { name: 'subject'; type: { kind: 'INTERFACE'; name: 'Node'; ofType: null; } }; 'subjectJson': { name: 'subjectJson'; type: { kind: 'SCALAR'; name: 'JSONObject'; ofType: null; } }; 'summary': { name: 'summary'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'user': { name: 'user'; type: { kind: 'OBJECT'; name: 'PersonNode'; ofType: null; } }; }; }; 'AuthSource': { name: 'AuthSource'; enumValues: 'Anonymous' | 'Demo' | 'LinkBlue' | 'None'; }; 'BatchType': { name: 'BatchType'; enumValues: 'ACH' | 'Check' | 'CreditCard' | 'DBFunds' | 'NonCash' | 'PayrollDeduction' | 'Transmittal' | 'Unknown'; }; 'Boolean': unknown; @@ -94,6 +94,7 @@ export type introspection_types = { 'IntervalISOInput': { kind: 'INPUT_OBJECT'; name: 'IntervalISOInput'; isOneOf: false; inputFields: [{ name: 'end'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'DateTimeISO'; ofType: null; }; }; defaultValue: null }, { name: 'start'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'DateTimeISO'; ofType: null; }; }; defaultValue: null }]; }; 'JSON': unknown; 'JSONObject': unknown; + 'ListAuditLogsResponse': { kind: 'OBJECT'; name: 'ListAuditLogsResponse'; fields: { 'data': { name: 'data'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'AuditLogNode'; ofType: null; }; } }; 'page': { name: 'page'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'PositiveInt'; ofType: null; }; } }; 'pageSize': { name: 'pageSize'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; 'total': { name: 'total'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; }; }; 'ListDailyDepartmentNotificationsResponse': { kind: 'OBJECT'; name: 'ListDailyDepartmentNotificationsResponse'; fields: { 'data': { name: 'data'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'DailyDepartmentNotificationNode'; ofType: null; }; }; }; } }; 'page': { name: 'page'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'PositiveInt'; ofType: null; }; } }; 'pageSize': { name: 'pageSize'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; 'total': { name: 'total'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; }; }; 'ListDevicesResponse': { kind: 'OBJECT'; name: 'ListDevicesResponse'; fields: { 'data': { name: 'data'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'DeviceNode'; ofType: null; }; }; }; } }; 'page': { name: 'page'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'PositiveInt'; ofType: null; }; } }; 'pageSize': { name: 'pageSize'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; 'total': { name: 'total'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; }; }; 'ListEventsResponse': { kind: 'OBJECT'; name: 'ListEventsResponse'; fields: { 'data': { name: 'data'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'EventNode'; ofType: null; }; }; }; } }; 'page': { name: 'page'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'PositiveInt'; ofType: null; }; } }; 'pageSize': { name: 'pageSize'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; 'total': { name: 'total'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'NonNegativeInt'; ofType: null; }; } }; }; }; @@ -170,7 +171,7 @@ export type introspection_types = { 'PointOpportunityResolverOneOfFilterKeys': { name: 'PointOpportunityResolverOneOfFilterKeys'; enumValues: 'marathonUuid' | 'type'; }; 'PointOpportunityResolverStringFilterKeys': { name: 'PointOpportunityResolverStringFilterKeys'; enumValues: 'name'; }; 'PositiveInt': unknown; - 'Query': { kind: 'OBJECT'; name: 'Query'; fields: { 'activeConfiguration': { name: 'activeConfiguration'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'GetConfigurationByUuidResponse'; ofType: null; }; } }; 'allConfigurations': { name: 'allConfigurations'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ConfigurationNode'; ofType: null; }; }; }; } }; 'auditLogs': { name: 'auditLogs'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'AuditLogNode'; ofType: null; }; }; }; } }; 'configuration': { name: 'configuration'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ConfigurationNode'; ofType: null; }; } }; 'currentMarathon': { name: 'currentMarathon'; type: { kind: 'OBJECT'; name: 'MarathonNode'; ofType: null; } }; 'currentMarathonHour': { name: 'currentMarathonHour'; type: { kind: 'OBJECT'; name: 'MarathonHourNode'; ofType: null; } }; 'dailyDepartmentNotification': { name: 'dailyDepartmentNotification'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'DailyDepartmentNotificationNode'; ofType: null; }; } }; 'dailyDepartmentNotificationBatch': { name: 'dailyDepartmentNotificationBatch'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'DailyDepartmentNotificationBatchNode'; ofType: null; }; } }; 'dailyDepartmentNotifications': { name: 'dailyDepartmentNotifications'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListDailyDepartmentNotificationsResponse'; ofType: null; }; } }; 'device': { name: 'device'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'GetDeviceByUuidResponse'; ofType: null; }; } }; 'devices': { name: 'devices'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListDevicesResponse'; ofType: null; }; } }; 'event': { name: 'event'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'EventNode'; ofType: null; }; } }; 'events': { name: 'events'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListEventsResponse'; ofType: null; }; } }; 'feed': { name: 'feed'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'INTERFACE'; name: 'FeedItem'; ofType: null; }; }; }; } }; 'feedItem': { name: 'feedItem'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'FeedNode'; ofType: null; }; } }; 'fundraisingAssignment': { name: 'fundraisingAssignment'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'FundraisingAssignmentNode'; ofType: null; }; } }; 'fundraisingEntries': { name: 'fundraisingEntries'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListFundraisingEntriesResponse'; ofType: null; }; } }; 'fundraisingEntry': { name: 'fundraisingEntry'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'FundraisingEntryNode'; ofType: null; }; } }; 'image': { name: 'image'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ImageNode'; ofType: null; }; } }; 'images': { name: 'images'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListImagesResponse'; ofType: null; }; } }; 'latestMarathon': { name: 'latestMarathon'; type: { kind: 'OBJECT'; name: 'MarathonNode'; ofType: null; } }; 'loginState': { name: 'loginState'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'LoginState'; ofType: null; }; } }; 'marathon': { name: 'marathon'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'MarathonNode'; ofType: null; }; } }; 'marathonForYear': { name: 'marathonForYear'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'MarathonNode'; ofType: null; }; } }; 'marathonHour': { name: 'marathonHour'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'MarathonHourNode'; ofType: null; }; } }; 'marathonHours': { name: 'marathonHours'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListMarathonHoursResponse'; ofType: null; }; } }; 'marathons': { name: 'marathons'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListMarathonsResponse'; ofType: null; }; } }; 'me': { name: 'me'; type: { kind: 'OBJECT'; name: 'PersonNode'; ofType: null; } }; 'node': { name: 'node'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'INTERFACE'; name: 'Node'; ofType: null; }; } }; 'notification': { name: 'notification'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'NotificationNode'; ofType: null; }; } }; 'notificationDeliveries': { name: 'notificationDeliveries'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListNotificationDeliveriesResponse'; ofType: null; }; } }; 'notifications': { name: 'notifications'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListNotificationsResponse'; ofType: null; }; } }; 'people': { name: 'people'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListPeopleResponse'; ofType: null; }; } }; 'person': { name: 'person'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PersonNode'; ofType: null; }; } }; 'personByLinkBlue': { name: 'personByLinkBlue'; type: { kind: 'OBJECT'; name: 'PersonNode'; ofType: null; } }; 'pointEntries': { name: 'pointEntries'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListPointEntriesResponse'; ofType: null; }; } }; 'pointEntry': { name: 'pointEntry'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PointEntryNode'; ofType: null; }; } }; 'pointOpportunities': { name: 'pointOpportunities'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListPointOpportunitiesResponse'; ofType: null; }; } }; 'pointOpportunity': { name: 'pointOpportunity'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PointOpportunityNode'; ofType: null; }; } }; 'rawFundraisingEntries': { name: 'rawFundraisingEntries'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'rawFundraisingTotals': { name: 'rawFundraisingTotals'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'report': { name: 'report'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'Report'; ofType: null; }; } }; 'searchPeopleByName': { name: 'searchPeopleByName'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PersonNode'; ofType: null; }; }; }; } }; 'solicitationCode': { name: 'solicitationCode'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'SolicitationCodeNode'; ofType: null; }; } }; 'solicitationCodes': { name: 'solicitationCodes'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListSolicitationCodesResponse'; ofType: null; }; } }; 'team': { name: 'team'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'TeamNode'; ofType: null; }; } }; 'teams': { name: 'teams'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListTeamsResponse'; ofType: null; }; } }; }; }; + 'Query': { kind: 'OBJECT'; name: 'Query'; fields: { 'activeConfiguration': { name: 'activeConfiguration'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'GetConfigurationByUuidResponse'; ofType: null; }; } }; 'allConfigurations': { name: 'allConfigurations'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ConfigurationNode'; ofType: null; }; }; }; } }; 'auditLogs': { name: 'auditLogs'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListAuditLogsResponse'; ofType: null; }; } }; 'configuration': { name: 'configuration'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ConfigurationNode'; ofType: null; }; } }; 'currentMarathon': { name: 'currentMarathon'; type: { kind: 'OBJECT'; name: 'MarathonNode'; ofType: null; } }; 'currentMarathonHour': { name: 'currentMarathonHour'; type: { kind: 'OBJECT'; name: 'MarathonHourNode'; ofType: null; } }; 'dailyDepartmentNotification': { name: 'dailyDepartmentNotification'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'DailyDepartmentNotificationNode'; ofType: null; }; } }; 'dailyDepartmentNotificationBatch': { name: 'dailyDepartmentNotificationBatch'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'DailyDepartmentNotificationBatchNode'; ofType: null; }; } }; 'dailyDepartmentNotifications': { name: 'dailyDepartmentNotifications'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListDailyDepartmentNotificationsResponse'; ofType: null; }; } }; 'device': { name: 'device'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'GetDeviceByUuidResponse'; ofType: null; }; } }; 'devices': { name: 'devices'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListDevicesResponse'; ofType: null; }; } }; 'event': { name: 'event'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'EventNode'; ofType: null; }; } }; 'events': { name: 'events'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListEventsResponse'; ofType: null; }; } }; 'feed': { name: 'feed'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'INTERFACE'; name: 'FeedItem'; ofType: null; }; }; }; } }; 'feedItem': { name: 'feedItem'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'FeedNode'; ofType: null; }; } }; 'fundraisingAssignment': { name: 'fundraisingAssignment'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'FundraisingAssignmentNode'; ofType: null; }; } }; 'fundraisingEntries': { name: 'fundraisingEntries'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListFundraisingEntriesResponse'; ofType: null; }; } }; 'fundraisingEntry': { name: 'fundraisingEntry'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'FundraisingEntryNode'; ofType: null; }; } }; 'image': { name: 'image'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ImageNode'; ofType: null; }; } }; 'images': { name: 'images'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListImagesResponse'; ofType: null; }; } }; 'latestMarathon': { name: 'latestMarathon'; type: { kind: 'OBJECT'; name: 'MarathonNode'; ofType: null; } }; 'loginState': { name: 'loginState'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'LoginState'; ofType: null; }; } }; 'marathon': { name: 'marathon'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'MarathonNode'; ofType: null; }; } }; 'marathonForYear': { name: 'marathonForYear'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'MarathonNode'; ofType: null; }; } }; 'marathonHour': { name: 'marathonHour'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'MarathonHourNode'; ofType: null; }; } }; 'marathonHours': { name: 'marathonHours'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListMarathonHoursResponse'; ofType: null; }; } }; 'marathons': { name: 'marathons'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListMarathonsResponse'; ofType: null; }; } }; 'me': { name: 'me'; type: { kind: 'OBJECT'; name: 'PersonNode'; ofType: null; } }; 'node': { name: 'node'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'INTERFACE'; name: 'Node'; ofType: null; }; } }; 'notification': { name: 'notification'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'NotificationNode'; ofType: null; }; } }; 'notificationDeliveries': { name: 'notificationDeliveries'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListNotificationDeliveriesResponse'; ofType: null; }; } }; 'notifications': { name: 'notifications'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListNotificationsResponse'; ofType: null; }; } }; 'people': { name: 'people'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListPeopleResponse'; ofType: null; }; } }; 'person': { name: 'person'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PersonNode'; ofType: null; }; } }; 'personByLinkBlue': { name: 'personByLinkBlue'; type: { kind: 'OBJECT'; name: 'PersonNode'; ofType: null; } }; 'pointEntries': { name: 'pointEntries'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListPointEntriesResponse'; ofType: null; }; } }; 'pointEntry': { name: 'pointEntry'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PointEntryNode'; ofType: null; }; } }; 'pointOpportunities': { name: 'pointOpportunities'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListPointOpportunitiesResponse'; ofType: null; }; } }; 'pointOpportunity': { name: 'pointOpportunity'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PointOpportunityNode'; ofType: null; }; } }; 'rawFundraisingEntries': { name: 'rawFundraisingEntries'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'rawFundraisingTotals': { name: 'rawFundraisingTotals'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'report': { name: 'report'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'Report'; ofType: null; }; } }; 'searchPeopleByName': { name: 'searchPeopleByName'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PersonNode'; ofType: null; }; }; }; } }; 'solicitationCode': { name: 'solicitationCode'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'SolicitationCodeNode'; ofType: null; }; } }; 'solicitationCodes': { name: 'solicitationCodes'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListSolicitationCodesResponse'; ofType: null; }; } }; 'team': { name: 'team'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'TeamNode'; ofType: null; }; } }; 'teams': { name: 'teams'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ListTeamsResponse'; ofType: null; }; } }; }; }; 'RegisterDeviceInput': { kind: 'INPUT_OBJECT'; name: 'RegisterDeviceInput'; isOneOf: false; inputFields: [{ name: 'deviceId'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }, { name: 'expoPushToken'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'lastUserId'; type: { kind: 'SCALAR'; name: 'GlobalId'; ofType: null; }; defaultValue: null }, { name: 'verifier'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }]; }; 'RegisterDeviceResponse': { kind: 'OBJECT'; name: 'RegisterDeviceResponse'; fields: { 'data': { name: 'data'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'DeviceNode'; ofType: null; }; } }; 'ok': { name: 'ok'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; } }; }; }; 'Report': { kind: 'OBJECT'; name: 'Report'; fields: { 'pages': { name: 'pages'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ReportPage'; ofType: null; }; }; }; } }; }; }; diff --git a/packages/portal/package.json b/packages/portal/package.json index 40449f77..0fcac165 100644 --- a/packages/portal/package.json +++ b/packages/portal/package.json @@ -53,7 +53,7 @@ "@urql/core": "^5.0.8", "@urql/devtools": "^2.0.3", "@wysimark/react": "^3.0.20", - "antd": "^5.22.3", + "antd": "^5.22.4", "camelcase": "^8.0.0", "class-validator": "^0.14.1", "gql.tada": "^1.8.10", diff --git a/packages/portal/src/config/refine/authorization.ts b/packages/portal/src/config/refine/authorization.ts index 7fd856e3..27deaedf 100644 --- a/packages/portal/src/config/refine/authorization.ts +++ b/packages/portal/src/config/refine/authorization.ts @@ -1,48 +1,22 @@ -import type { AccessControlProvider } from "@refinedev/core"; +import type { AccessControlProvider, CanParams } from "@refinedev/core"; import type { Action } from "@ukdanceblue/common"; import { urqlClient } from "#config/api.ts"; +import type { PortalAuthData } from "#hooks/useLoginState.ts"; import { getLoginState } from "#hooks/useLoginState.ts"; export const accessControlProvider: AccessControlProvider = { - can: ({ action, params }) => { + // eslint-disable-next-line @typescript-eslint/require-await + can: async (param) => { const loginState = getLoginState(urqlClient); if (loginState.isErr()) { - return Promise.resolve({ can: false }); + return { can: false }; } - const ok = loginState.value.ability.can( - action === "clone" - ? "create" - : action === "edit" - ? "update" - : action === "show" - ? "get" - : (action as Action), - params?.resource?.meta?.modelName - ? { - id: params.id ? String(params.id) : undefined, - kind: params.resource.meta.modelName as "FundraisingAssignmentNode", - } - : "all" - ); - - console.log("Checking access control", { - authorized: ok, - action, - subject: params?.resource?.meta?.modelName - ? { - id: params.id ? String(params.id) : undefined, - kind: params.resource.meta.modelName as "FundraisingAssignmentNode", - } - : "all", - params, - }); - - return Promise.resolve({ - can: ok, - }); + return { + can: canSync(param, loginState.value), + }; }, options: { buttons: { @@ -54,3 +28,26 @@ export const accessControlProvider: AccessControlProvider = { }, }, }; + +export function canSync( + { action, params }: CanParams, + loginState: PortalAuthData +): boolean { + const ok = loginState.ability.can( + action === "clone" + ? "create" + : action === "edit" + ? "update" + : action === "show" + ? "get" + : (action as Action), + params?.resource?.meta?.modelName + ? { + id: params.id ? String(params.id) : undefined, + kind: params.resource.meta.modelName as "FundraisingAssignmentNode", + } + : "all" + ); + + return ok; +} diff --git a/packages/portal/src/elements/components/sider/index.tsx b/packages/portal/src/elements/components/sider/index.tsx index 5072a598..ef2b43d2 100644 --- a/packages/portal/src/elements/components/sider/index.tsx +++ b/packages/portal/src/elements/components/sider/index.tsx @@ -1,6 +1,5 @@ import { BarsOutlined, - DashboardOutlined, LogoutOutlined, UnorderedListOutlined, } from "@ant-design/icons"; @@ -9,182 +8,167 @@ import { Title as DefaultTitle, } from "@refinedev/antd"; import { - CanAccess, - type ITreeMenu, - pickNotDeprecated, - useActiveAuthProvider, useIsExistAuthentication, useLink, useLogout, useMenu, - useRefineContext, - useRouterContext, - useRouterType, useTitle, useTranslate, useWarnAboutChange, } from "@refinedev/core"; import { Button, ConfigProvider, Drawer, Grid, Layout, Menu } from "antd"; -import React, { useState } from "react"; +import type { ItemType } from "antd/es/menu/interface"; +import React, { useMemo, useState } from "react"; + +import { canSync } from "#config/refine/authorization.ts"; +import { StorageManager, useStorageValue } from "#config/storage.ts"; +import { useLoginState } from "#hooks/useLoginState.ts"; import { drawerButtonStyles } from "./styles"; export const Sider: React.FC< RefineLayoutSiderProps & { - collapsed?: boolean; - setCollapsed?: (collapsed: boolean) => void; + getItems?: (props: { + items: ItemType[]; + logout: ItemType | false; + collapsed: boolean; + }) => ItemType[]; } -> = ({ - Title: TitleFromProps, - render, - meta, - collapsed = false, - setCollapsed = () => undefined, -}) => { +> = ({ Title: TitleFromProps, getItems, meta }) => { const [drawerOpen, setDrawerOpen] = useState(false); + const [menuCollapsed, setMenuCollapsed] = useStorageValue( + StorageManager.Local, + StorageManager.keys.collapseSidebar, + "true" + ); + const isExistAuthentication = useIsExistAuthentication(); - const routerType = useRouterType(); - const NewLink = useLink(); + const Link = useLink(); const { warnWhen, setWarnWhen } = useWarnAboutChange(); - const { Link: LegacyLink } = useRouterContext(); - const Link = routerType === "legacy" ? LegacyLink : NewLink; const TitleFromContext = useTitle(); const translate = useTranslate(); const { menuItems, selectedKey, defaultOpenKeys } = useMenu({ meta }); const breakpoint = Grid.useBreakpoint(); - const { hasDashboard } = useRefineContext(); - const authProvider = useActiveAuthProvider(); - const { mutate: mutateLogout } = useLogout({ - v3LegacyAuthProviderCompatible: Boolean(authProvider?.isLegacy), - }); + const { mutate: mutateLogout } = useLogout(); + const loginState = useLoginState(); const isMobile = breakpoint.lg === undefined ? false : !breakpoint.lg; const RenderToTitle = TitleFromProps ?? TitleFromContext ?? DefaultTitle; - const renderTreeView = (tree: ITreeMenu[], selectedKey?: string) => { - return tree.map((item: ITreeMenu) => { - const { - icon, - label, - route, - key, - name, - children, - parentName, - meta, - options, - } = item; + const items = useMemo((): ItemType[] => { + function makeItem( + treeItem: (typeof menuItems)[number] + ): ItemType | undefined { + const { key, name, children, meta, list } = treeItem; + + const visible = canSync( + { + action: "list", + params: { + resource: treeItem, + }, + resource: name, + }, + loginState + ); + + if (!visible) { + return; + } if (children.length > 0) { - return ( - - } - title={label} - > - {renderTreeView(children, selectedKey)} - - - ); + return { + key, + icon: meta?.icon ?? , + type: "submenu", + label: meta?.label, + children: makeChildren(children), + }; } + const isSelected = key === selectedKey; - const isRoute = !( - pickNotDeprecated(meta?.parent, options?.parent, parentName) !== - undefined && children.length === 0 - ); - return ( - - )} - > - {label} - {!collapsed && isSelected && ( + const isRoute = !(meta?.parent !== undefined && children.length === 0); + return { + key, + icon: meta?.icon ?? (isRoute && ), + style: { + fontWeight: isSelected ? "bold" : "normal", + }, + label: ( + <> + {meta?.label} + {!menuCollapsed && isSelected && (
)} - - - ); - }); - }; - - const handleLogout = () => { - if (warnWhen) { - const confirm = window.confirm( - translate( - "warnWhenUnsavedChanges", - "Are you sure you want to leave? You have unsaved changes." - ) - ); + + ), + }; + } - if (confirm) { - setWarnWhen(false); - mutateLogout(); + function makeChildren(tree: typeof menuItems): ItemType[] { + const menuTree: ItemType[] = []; + for (const item of tree) { + const menuItem = makeItem(item); + if (menuItem) { + menuTree.push(menuItem); + } } - } else { - mutateLogout(); + return menuTree; } - }; - const logout = isExistAuthentication && ( - }> - {translate("buttons.logout", "Logout")} - - ); + return makeChildren(menuItems); + }, [Link, loginState, menuCollapsed, menuItems, selectedKey]); - const dashboard = hasDashboard ? ( - } - > - {translate("dashboard.title", "Dashboard")} - {!collapsed && selectedKey === "/" && ( -
- )} - - ) : null; + const siderItems = useMemo((): ItemType[] => { + const handleLogout = () => { + if (warnWhen) { + const confirm = window.confirm( + translate( + "warnWhenUnsavedChanges", + "Are you sure you want to leave? You have unsaved changes." + ) + ); + + if (confirm) { + setWarnWhen(false); + mutateLogout(); + } + } else { + mutateLogout(); + } + }; - const items = renderTreeView(menuItems, selectedKey); + const logout: ItemType | false = isExistAuthentication && { + key: "logout", + icon: , + onClick: handleLogout, + label: translate("buttons.logout", "Logout"), + }; - const renderSider = () => { - if (render) { - return render({ - dashboard, + if (getItems) { + return getItems({ items, logout, - collapsed, + collapsed: menuCollapsed === "true", }); } - return ( - <> - {dashboard} - {items} - {logout} - - ); - }; + + const itemList: ItemType[] = [...items]; + if (logout) { + itemList.push(logout); + } + return itemList; + }, [ + getItems, + isExistAuthentication, + items, + menuCollapsed, + mutateLogout, + setWarnWhen, + translate, + warnWhen, + ]); const renderMenu = () => { return ( @@ -197,71 +181,15 @@ export const Sider: React.FC< onClick={() => { setDrawerOpen(false); if (!breakpoint.lg) { - setCollapsed(true); + setMenuCollapsed("true"); } }} - > - {renderSider()} - - - ); - }; - - const renderDrawerSider = () => { - return ( - <> - setDrawerOpen(false)} - placement="left" - closable={false} - width={200} - bodyStyle={{ - padding: 0, - }} - maskClosable={true} - > - - - - {renderMenu()} - - - -