diff --git a/assets/approval-requests-bundle.js b/assets/approval-requests-bundle.js index ee26b3936..47032c726 100644 --- a/assets/approval-requests-bundle.js +++ b/assets/approval-requests-bundle.js @@ -45,6 +45,7 @@ function useSearchApprovalRequests() { return { approvalRequests, errorFetchingApprovalRequests: error, + approvalRequestStatus, setApprovalRequestStatus, isLoading: isLoading, }; @@ -70,7 +71,14 @@ const StyledMediaInput = styled(MediaInput) ` const DropdownFilterField = styled(Field) ` flex: 1; `; -function ApprovalRequestListFilters({ setApprovalRequestStatus, setSearchTerm, }) { +const ApprovalRequestStatusInputMap = { + any: "Any", + active: "Decision pending", + approved: "Approved", + rejected: "Denied", + withdrawn: "Withdrawn", +}; +function ApprovalRequestListFilters({ approvalRequestStatus, setApprovalRequestStatus, setSearchTerm, }) { const handleChange = reactExports.useCallback((changes) => { if (!changes.selectionValue) { return; @@ -82,7 +90,7 @@ function ApprovalRequestListFilters({ setApprovalRequestStatus, setSearchTerm, } const handleSearch = reactExports.useCallback((event) => { debouncedSetSearchTerm(event.target.value); }, [debouncedSetSearchTerm]); - return (jsxRuntimeExports.jsxs(FiltersContainer, { children: [jsxRuntimeExports.jsxs(SearchField, { children: [jsxRuntimeExports.jsx(Label, { hidden: true, children: "Search approval requests" }), jsxRuntimeExports.jsx(StyledMediaInput, { start: jsxRuntimeExports.jsx(SvgSearchStroke, {}), placeholder: "Search approval requests", onChange: handleSearch })] }), jsxRuntimeExports.jsxs(DropdownFilterField, { children: [jsxRuntimeExports.jsx(Label, { children: "Status:" }), jsxRuntimeExports.jsxs(Combobox, { isEditable: false, onChange: handleChange, children: [jsxRuntimeExports.jsx(Option, { value: "any", isSelected: true, label: "Any" }), jsxRuntimeExports.jsx(Option, { value: "active", label: "Decision pending" }), jsxRuntimeExports.jsx(Option, { value: "approved", label: "Approved" }), jsxRuntimeExports.jsx(Option, { value: "rejected", label: "Denied" }), jsxRuntimeExports.jsx(Option, { value: "withdrawn", label: "Withdrawn" })] })] })] })); + return (jsxRuntimeExports.jsxs(FiltersContainer, { children: [jsxRuntimeExports.jsxs(SearchField, { children: [jsxRuntimeExports.jsx(Label, { hidden: true, children: "Search approval requests" }), jsxRuntimeExports.jsx(StyledMediaInput, { start: jsxRuntimeExports.jsx(SvgSearchStroke, {}), placeholder: "Search approval requests", onChange: handleSearch })] }), jsxRuntimeExports.jsxs(DropdownFilterField, { children: [jsxRuntimeExports.jsx(Label, { children: "Status:" }), jsxRuntimeExports.jsxs(Combobox, { isEditable: false, onChange: handleChange, selectionValue: approvalRequestStatus, inputValue: ApprovalRequestStatusInputMap[approvalRequestStatus], children: [jsxRuntimeExports.jsx(Option, { value: "any", label: "Any" }), jsxRuntimeExports.jsx(Option, { value: "active", label: "Decision pending" }), jsxRuntimeExports.jsx(Option, { value: "approved", label: "Approved" }), jsxRuntimeExports.jsx(Option, { value: "rejected", label: "Denied" }), jsxRuntimeExports.jsx(Option, { value: "withdrawn", label: "Withdrawn" })] })] })] })); } var ApprovalRequestListFilters$1 = reactExports.memo(ApprovalRequestListFilters); @@ -144,7 +152,7 @@ const LoadingContainer$1 = styled.div ` `; function ApprovalRequestListPage({ baseLocale, helpCenterPath, }) { const [searchTerm, setSearchTerm] = reactExports.useState(""); - const { approvalRequests, errorFetchingApprovalRequests: error, setApprovalRequestStatus, isLoading, } = useSearchApprovalRequests(); + const { approvalRequests, errorFetchingApprovalRequests: error, approvalRequestStatus, setApprovalRequestStatus, isLoading, } = useSearchApprovalRequests(); const filteredRequests = reactExports.useMemo(() => { if (!searchTerm) return approvalRequests; @@ -157,7 +165,7 @@ function ApprovalRequestListPage({ baseLocale, helpCenterPath, }) { if (isLoading) { return (jsxRuntimeExports.jsx(LoadingContainer$1, { children: jsxRuntimeExports.jsx(Spinner, { size: "64" }) })); } - return (jsxRuntimeExports.jsxs(Container$2, { children: [jsxRuntimeExports.jsx(XXL, { isBold: true, children: "Approval requests" }), jsxRuntimeExports.jsx(ApprovalRequestListFilters$1, { setApprovalRequestStatus: setApprovalRequestStatus, setSearchTerm: setSearchTerm }), jsxRuntimeExports.jsx(ApprovalRequestListTable$1, { requests: filteredRequests, baseLocale: baseLocale, helpCenterPath: helpCenterPath })] })); + return (jsxRuntimeExports.jsxs(Container$2, { children: [jsxRuntimeExports.jsx(XXL, { isBold: true, children: "Approval requests" }), jsxRuntimeExports.jsx(ApprovalRequestListFilters$1, { approvalRequestStatus: approvalRequestStatus, setApprovalRequestStatus: setApprovalRequestStatus, setSearchTerm: setSearchTerm }), jsxRuntimeExports.jsx(ApprovalRequestListTable$1, { requests: filteredRequests, baseLocale: baseLocale, helpCenterPath: helpCenterPath })] })); } var ApprovalRequestListPage$1 = reactExports.memo(ApprovalRequestListPage); @@ -184,7 +192,7 @@ const DetailRow = styled(Row$1) ` } `; function ApprovalRequestDetails({ approvalRequest, baseLocale, }) { - return (jsxRuntimeExports.jsxs(Container$1, { children: [jsxRuntimeExports.jsx(ApprovalRequestHeader, { isBold: true, children: "Approval request details" }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Sent by" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.created_by_user.name }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Sent on" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: formatApprovalRequestDate(approvalRequest.created_at, baseLocale) }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Approver" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.assignee_user.name }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Status" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: jsxRuntimeExports.jsx(ApprovalStatusTag$1, { status: approvalRequest.status }) }) })] })] })); + return (jsxRuntimeExports.jsxs(Container$1, { children: [jsxRuntimeExports.jsx(ApprovalRequestHeader, { isBold: true, children: "Approval request details" }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Sent by" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.created_by_user.name }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Sent on" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: formatApprovalRequestDate(approvalRequest.created_at, baseLocale) }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Approver" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.assignee_user.name }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Status" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: jsxRuntimeExports.jsx(ApprovalStatusTag$1, { status: approvalRequest.status }) }) })] }), approvalRequest.decided_at && (jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Decided" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: formatApprovalRequestDate(approvalRequest.decided_at, baseLocale) }) })] })), approvalRequest.decision_notes.length > 0 && (jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Comment" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.decision_notes[0] }) })] }))] })); } var ApprovalRequestDetails$1 = reactExports.memo(ApprovalRequestDetails); @@ -213,7 +221,11 @@ const CustomFieldsGrid = styled.div ` grid-template-columns: repeat(2, 1fr); } `; +const NULL_VALUE_PLACEHOLDER = "-"; function CustomFieldValue({ value, }) { + if (!value) { + return jsxRuntimeExports.jsx(MD, { children: NULL_VALUE_PLACEHOLDER }); + } if (Array.isArray(value)) { return (jsxRuntimeExports.jsx(MD, { children: value.map((val) => (jsxRuntimeExports.jsx(MultiselectTag, { hue: "grey", children: val }, val))) })); } diff --git a/src/modules/approval-requests/ApprovalRequestListPage.tsx b/src/modules/approval-requests/ApprovalRequestListPage.tsx index a7c5d8f64..c0dc946ea 100644 --- a/src/modules/approval-requests/ApprovalRequestListPage.tsx +++ b/src/modules/approval-requests/ApprovalRequestListPage.tsx @@ -31,6 +31,7 @@ function ApprovalRequestListPage({ const { approvalRequests, errorFetchingApprovalRequests: error, + approvalRequestStatus, setApprovalRequestStatus, isLoading, } = useSearchApprovalRequests(); @@ -60,6 +61,7 @@ function ApprovalRequestListPage({ Approval requests diff --git a/src/modules/approval-requests/components/approval-request-list/ApprovalRequestListFilters.tsx b/src/modules/approval-requests/components/approval-request-list/ApprovalRequestListFilters.tsx index 4794b937f..5fb51d369 100644 --- a/src/modules/approval-requests/components/approval-request-list/ApprovalRequestListFilters.tsx +++ b/src/modules/approval-requests/components/approval-request-list/ApprovalRequestListFilters.tsx @@ -42,7 +42,16 @@ const DropdownFilterField = styled(Field)` flex: 1; `; +const ApprovalRequestStatusInputMap = { + any: "Any", + active: "Decision pending", + approved: "Approved", + rejected: "Denied", + withdrawn: "Withdrawn", +}; + interface ApprovalRequestListFiltersProps { + approvalRequestStatus: ApprovalRequestDropdownStatus; setApprovalRequestStatus: Dispatch< SetStateAction >; @@ -50,6 +59,7 @@ interface ApprovalRequestListFiltersProps { } function ApprovalRequestListFilters({ + approvalRequestStatus, setApprovalRequestStatus, setSearchTerm, }: ApprovalRequestListFiltersProps) { @@ -91,8 +101,13 @@ function ApprovalRequestListFilters({ - - ); } diff --git a/src/modules/approval-requests/components/approval-request/ApprovalTicketDetails.tsx b/src/modules/approval-requests/components/approval-request/ApprovalTicketDetails.tsx index c42f54225..87cb4d0fb 100644 --- a/src/modules/approval-requests/components/approval-request/ApprovalTicketDetails.tsx +++ b/src/modules/approval-requests/components/approval-request/ApprovalTicketDetails.tsx @@ -3,8 +3,8 @@ import styled from "styled-components"; import { MD } from "@zendeskgarden/react-typography"; import { getColorV8 } from "@zendeskgarden/react-theming"; import { Grid } from "@zendeskgarden/react-grid"; -import type { MockTicket } from "../../types"; import { Tag } from "@zendeskgarden/react-tags"; +import type { ApprovalRequestTicket } from "../../types"; const TicketContainer = styled(Grid)` padding: ${(props) => props.theme.space.md}; /* 20px */ @@ -36,11 +36,16 @@ const CustomFieldsGrid = styled.div` } `; +const NULL_VALUE_PLACEHOLDER = "-"; + function CustomFieldValue({ value, }: { value: string | boolean | Array | undefined; }) { + if (!value) { + return {NULL_VALUE_PLACEHOLDER}; + } if (Array.isArray(value)) { return ( @@ -61,7 +66,7 @@ function CustomFieldValue({ } interface ApprovalTicketDetailsProps { - ticket: MockTicket; + ticket: ApprovalRequestTicket; } function ApprovalTicketDetails({ ticket }: ApprovalTicketDetailsProps) { diff --git a/src/modules/approval-requests/hooks/useSearchApprovalRequests.tsx b/src/modules/approval-requests/hooks/useSearchApprovalRequests.tsx index 4f1e9b51f..6459c8e66 100644 --- a/src/modules/approval-requests/hooks/useSearchApprovalRequests.tsx +++ b/src/modules/approval-requests/hooks/useSearchApprovalRequests.tsx @@ -7,6 +7,7 @@ import type { export function useSearchApprovalRequests(): { approvalRequests: SearchApprovalRequest[]; errorFetchingApprovalRequests: unknown; + approvalRequestStatus: ApprovalRequestDropdownStatus; setApprovalRequestStatus: Dispatch< SetStateAction >; @@ -66,6 +67,7 @@ export function useSearchApprovalRequests(): { return { approvalRequests, errorFetchingApprovalRequests: error, + approvalRequestStatus, setApprovalRequestStatus, isLoading: isLoading, }; diff --git a/src/modules/approval-requests/types.ts b/src/modules/approval-requests/types.ts index 29064998d..a0cfbef56 100644 --- a/src/modules/approval-requests/types.ts +++ b/src/modules/approval-requests/types.ts @@ -21,8 +21,10 @@ export interface ApprovalRequest { message: string; status: ApprovalRequestStatus; created_at: string; - assignee_user: ApprovalRequestUser; created_by_user: ApprovalRequestUser; + decided_at: string | null; + decision_notes: string[]; + assignee_user: ApprovalRequestUser; ticket_details: ApprovalRequestTicket; }