Skip to content

Commit 05fec24

Browse files
committed
feat: display on-hold codes and definitions on authorization views
Updates frontend authorization components to support and display `PiesOnHold` status values. It adds a warning banner to show the current hold reason and its definition. - Add warning banner to `AuthorizationCard` and `AuthorizationStatusUpdatesCard` when a permit is on hold - Pull `codeDefinition` from `useCodeStore` to supply description text to hold messages - Pass `onHoldCode` down to the form lifecycle component wrappers - Clean up nested structural markup and class styling variables in `AuthorizationStatePill` Signed-off-by: qhanson55 <quinn.hanson@gov.bc.ca>
1 parent d3fa8f2 commit 05fec24

8 files changed

Lines changed: 494 additions & 205 deletions

File tree

frontend/src/components/authorization/AuthorizationCard.vue

Lines changed: 140 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
44
55
import AuthorizationStatePill from '@/components/authorization/AuthorizationStatePill.vue';
66
import StatusPill from '@/components/common/StatusPill.vue';
7-
import { Button, Card, useToast } from '@/lib/primevue';
7+
import { Button, Card, Message, useToast } from '@/lib/primevue';
88
import { useCodeStore } from '@/store';
99
import { PermitState } from '@/utils/enums/codeEnums';
1010
import { formatDate, formatDateOnly, formatDateTime } from '@/utils/formatters';
@@ -27,7 +27,7 @@ const trackingNotShownToProponent = computed(() => permit.permitTracking?.filter
2727
const trackingShownToProponent = computed(() => permit.permitTracking?.find((pt) => pt.shownToProponent));
2828
2929
// Store
30-
const { codeDisplay } = useCodeStore();
30+
const { codeDefinition, codeDisplay } = useCodeStore();
3131
3232
// Actions
3333
const toast = useToast();
@@ -42,135 +42,165 @@ function toCopy(toCopy: string) {
4242
<Card>
4343
<template #title>
4444
<div
45-
class="flex justify-between cursor-pointer hover:underline"
45+
class="flex justify-between cursor-pointer hover:underline mb-1 mt-3 mx-2"
4646
@click="emit('authorizationCard:more')"
4747
>
4848
<h4 class="mb-0">{{ permit.permitType?.name }}</h4>
4949
<Button
50-
class="p-button-outlined mr-4 mb-4 size-fit"
50+
class="p-button-outlined size-fit"
5151
:label="t('authorization.authorizationCard.more')"
5252
@click="emit('authorizationCard:more')"
5353
/>
5454
</div>
5555
</template>
5656
<template #content>
57-
<div class="flex gap-2">
58-
<span :class="permit.state !== PermitState.NONE ? 'pb-4' : ''">
59-
<AuthorizationStatePill
60-
v-if="permit.state !== PermitState.NONE"
61-
:state="permit.state"
62-
/>
63-
</span>
64-
<StatusPill
65-
:status="codeDisplay.PermitStage?.[permit.stage]"
66-
:border-color="'var(--p-support-info-border)'"
67-
:bg-color="'var(--p-support-info-surface)'"
68-
/>
69-
</div>
70-
<div class="grid grid-cols-[1fr_1fr_1fr] pt-2 pb-2 pr-2 gap-4">
71-
<div class="bg-[var(--p-bcblue-50)] py-5 pl-5">
72-
<div class="mb-2 text-xs">{{ t('authorization.authorizationCard.ids') }}</div>
73-
<div
74-
v-if="trackingShownToProponent"
75-
class="my-2"
76-
>
57+
<div class="mb-3 mx-2">
58+
<Message
59+
v-if="permit.onHoldCode"
60+
class="mb-4"
61+
severity="warn"
62+
:pt:content:class="['!px-2', '!py-2.5']"
63+
>
64+
<div class="flex items-center gap-2">
7765
<font-awesome-icon
78-
class="mr-2"
79-
icon="fa-solid fa-eye"
66+
class="text-[color:var(--p-support-warning-icon)]"
67+
icon="fas fa-circle-exclamation"
8068
/>
81-
<span
82-
v-tooltip.right="t('authorization.authorizationCard.clickToCopy')"
83-
class="cursor-pointer"
84-
@click="toCopy(trackingShownToProponent.trackingId as string)"
85-
>
86-
<span class="font-bold">
87-
{{ trackingShownToProponent.sourceSystemKind?.description }}
69+
<div class="flex flex-col">
70+
<strong class="text-xs">
71+
{{
72+
t('authorization.authorizationCard.onHoldReason', {
73+
reason: codeDisplay.PiesOnHold?.[permit.onHoldCode]
74+
})
75+
}}
76+
</strong>
77+
<span class="text-xs">
78+
{{
79+
t('authorization.authorizationCard.onHoldDefinition', {
80+
definition: codeDefinition.PiesOnHold?.[permit.onHoldCode]
81+
})
82+
}}
8883
</span>
89-
:
90-
{{ trackingShownToProponent.trackingId }}
91-
</span>
92-
</div>
93-
<div
94-
v-for="permitTracking in trackingNotShownToProponent"
95-
:key="permitTracking.permitTrackingId"
96-
class="my-2"
97-
>
98-
<span
99-
v-tooltip.right="t('authorization.authorizationCard.clickToCopy')"
100-
class="cursor-pointer"
101-
@click="toCopy(permitTracking.trackingId as string)"
102-
>
103-
<span class="font-bold">{{ permitTracking.sourceSystemKind?.description }}</span>
104-
:
105-
{{ permitTracking.trackingId }}
106-
</span>
107-
</div>
108-
<div>
109-
<span
110-
v-tooltip.right="t('authorization.authorizationCard.clickToCopy')"
111-
class="cursor-pointer"
112-
@click="toCopy(permit.issuedPermitId as string)"
113-
>
114-
<span class="font-bold">{{ t('authorization.authorizationCard.issuedPermitId') }}:</span>
115-
{{ permit.issuedPermitId }}
116-
</span>
84+
</div>
11785
</div>
86+
</Message>
87+
<div class="flex gap-2 pb-4">
88+
<AuthorizationStatePill
89+
v-if="permit.state !== PermitState.NONE"
90+
:state="permit.state"
91+
/>
92+
93+
<StatusPill
94+
:status="codeDisplay.PermitStage?.[permit.stage]"
95+
:border-color="'var(--p-support-info-border)'"
96+
:bg-color="'var(--p-support-info-surface)'"
97+
/>
11898
</div>
119-
<div class="bg-[var(--p-bcblue-50)] py-5 px-4">
120-
<div class="text-xs">{{ t('authorization.authorizationCard.dates') }}</div>
121-
<div class="my-2">
122-
<span class="font-bold">{{ t('authorization.authorizationCard.statusVerified') }}:</span>
123-
<span
124-
v-if="permit.statusLastVerified"
125-
class="ml-1"
99+
<div class="grid grid-cols-[1fr_1fr_1fr] pt-2 pb-2 pr-2 gap-4">
100+
<div class="bg-[var(--p-bcblue-50)] py-5 pl-5">
101+
<div class="mb-2 text-xs">{{ t('authorization.authorizationCard.ids') }}</div>
102+
<div
103+
v-if="trackingShownToProponent"
104+
class="my-2"
126105
>
127-
{{ formatDateOnly(permit.statusLastVerified) }}
128-
</span>
129-
</div>
130-
<div class="my-2">
131-
<span class="font-bold">{{ t('authorization.common.statusChangeDate') }}:</span>
132-
<span
133-
v-if="permit.statusLastChanged"
134-
class="ml-1"
135-
>
136-
{{ formatDateOnly(permit.statusLastChanged) }}
137-
</span>
138-
</div>
139-
<div class="my-2">
140-
<span class="font-bold">{{ t('authorization.common.submittedDate') }}:</span>
141-
<span
142-
v-if="permit.submittedDate"
143-
class="ml-1"
106+
<font-awesome-icon
107+
class="mr-2"
108+
icon="fa-solid fa-eye"
109+
/>
110+
<span
111+
v-tooltip.right="t('authorization.authorizationCard.clickToCopy')"
112+
class="cursor-pointer"
113+
@click="toCopy(trackingShownToProponent.trackingId as string)"
114+
>
115+
<span class="font-bold">
116+
{{ trackingShownToProponent.sourceSystemKind?.description }}
117+
</span>
118+
:
119+
{{ trackingShownToProponent.trackingId }}
120+
</span>
121+
</div>
122+
<div
123+
v-for="permitTracking in trackingNotShownToProponent"
124+
:key="permitTracking.permitTrackingId"
125+
class="my-2"
144126
>
145-
{{ formatDateOnly(permit.submittedDate) }}
146-
</span>
127+
<span
128+
v-tooltip.right="t('authorization.authorizationCard.clickToCopy')"
129+
class="cursor-pointer"
130+
@click="toCopy(permitTracking.trackingId as string)"
131+
>
132+
<span class="font-bold">{{ permitTracking.sourceSystemKind?.description }}</span>
133+
:
134+
{{ permitTracking.trackingId }}
135+
</span>
136+
</div>
137+
<div>
138+
<span
139+
v-tooltip.right="t('authorization.authorizationCard.clickToCopy')"
140+
class="cursor-pointer"
141+
@click="toCopy(permit.issuedPermitId as string)"
142+
>
143+
<span class="font-bold">{{ t('authorization.authorizationCard.issuedPermitId') }}:</span>
144+
{{ permit.issuedPermitId }}
145+
</span>
146+
</div>
147147
</div>
148-
<div class="my-2">
149-
<span class="font-bold">{{ t('authorization.common.decisionDate') }}:</span>
150-
<span
151-
v-if="permit.decisionDate"
152-
class="ml-1"
153-
>
154-
{{ formatDateOnly(permit.decisionDate) }}
155-
</span>
148+
<div class="bg-[var(--p-bcblue-50)] py-5 px-4">
149+
<div class="text-xs">{{ t('authorization.authorizationCard.dates') }}</div>
150+
<div class="my-2">
151+
<span class="font-bold">{{ t('authorization.authorizationCard.statusVerified') }}:</span>
152+
<span
153+
v-if="permit.statusLastVerified"
154+
class="ml-1"
155+
>
156+
{{ formatDateOnly(permit.statusLastVerified) }}
157+
</span>
158+
</div>
159+
<div class="my-2">
160+
<span class="font-bold">{{ t('authorization.common.statusChangeDate') }}:</span>
161+
<span
162+
v-if="permit.statusLastChanged"
163+
class="ml-1"
164+
>
165+
{{ formatDateOnly(permit.statusLastChanged) }}
166+
</span>
167+
</div>
168+
<div class="my-2">
169+
<span class="font-bold">{{ t('authorization.common.submittedDate') }}:</span>
170+
<span
171+
v-if="permit.submittedDate"
172+
class="ml-1"
173+
>
174+
{{ formatDateOnly(permit.submittedDate) }}
175+
</span>
176+
</div>
177+
<div class="my-2">
178+
<span class="font-bold">{{ t('authorization.common.decisionDate') }}:</span>
179+
<span
180+
v-if="permit.decisionDate"
181+
class="ml-1"
182+
>
183+
{{ formatDateOnly(permit.decisionDate) }}
184+
</span>
185+
</div>
186+
<div class="my-2">
187+
<span class="font-bold">{{ t('authorization.common.targetDate') }}:</span>
188+
<span
189+
v-if="permit.targetDate"
190+
class="ml-1"
191+
>
192+
{{ formatDate(permit.targetDate) }}
193+
</span>
194+
</div>
156195
</div>
157-
<div class="my-2">
158-
<span class="font-bold">{{ t('authorization.common.targetDate') }}:</span>
159-
<span
160-
v-if="permit.targetDate"
161-
class="ml-1"
162-
>
163-
{{ formatDate(permit.targetDate) }}
164-
</span>
196+
<div
197+
v-if="permit.permitNote?.length"
198+
class="pb-2 mt-2 mr-3"
199+
>
200+
<span>{{ ' ' + formatDateTime(permit.permitNote[0]!.createdAt) }},</span>
201+
{{ permit.permitNote[0]!.note }}
165202
</div>
166203
</div>
167-
<div
168-
v-if="permit.permitNote?.length"
169-
class="pb-2 mt-2 mr-3"
170-
>
171-
<span>{{ ' ' + formatDateTime(permit.permitNote[0]!.createdAt) }},</span>
172-
{{ permit.permitNote[0]!.note }}
173-
</div>
174204
</div>
175205
</template>
176206
</Card>

frontend/src/components/authorization/AuthorizationForm.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,8 @@ async function onSubmit(data: GenericObject) {
391391
}
392392
});
393393
} catch (e) {
394-
if (e instanceof Error) toast.error(t('authorization.authorizationForm.permitSaveFailed'), e.message);
394+
const message = e instanceof Error ? e.message : String(e);
395+
toast.error(t('authorization.authorizationForm.permitSaveFailed'), message);
395396
}
396397
}
397398
@@ -444,6 +445,7 @@ watch(() => isPeachIntegrated.value, handlePeachIntegrationChange, { immediate:
444445
:editable="editable"
445446
:peach-integrated-auth-type="isPeachIntegratedAuthType && isPeachEnabled"
446447
:peach-integrated-tracking-id="isPeachIntegratedTrackingId && isPeachEnabled"
448+
:on-hold-code="authorization?.onHoldCode"
447449
:show-target-date-description="!!values?.targetDate"
448450
class="mt-7"
449451
@update:set-verified-date="setFieldValue('statusLastVerified', new Date())"

frontend/src/components/authorization/AuthorizationStatePill.vue

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -112,35 +112,33 @@ const { codeDisplay } = useCodeStore();
112112
</script>
113113

114114
<template>
115-
<div class="flex">
115+
<div
116+
v-tooltip.right="getState?.toolTip"
117+
class="flex justify-center items-center rounded auth-indicator"
118+
:class="[getState?.badgeClass]"
119+
:style="{
120+
'--font-size': dimensions.fontSize,
121+
'--icon-font-size': dimensions.iconFontSize,
122+
'--height': dimensions.height,
123+
'--line-height': dimensions.lineHeight
124+
}"
125+
>
116126
<div
117-
v-tooltip.right="getState?.toolTip"
118-
class="flex justify-center items-center rounded auth-indicator"
119-
:class="[getState?.badgeClass]"
120-
:style="{
121-
'--font-size': dimensions.fontSize,
122-
'--icon-font-size': dimensions.iconFontSize,
123-
'--height': dimensions.height,
124-
'--line-height': dimensions.lineHeight
125-
}"
127+
v-tooltip.focus.right="getState?.toolTip"
128+
tabindex="0"
129+
:aria-label="getState?.toolTip"
130+
class="flex items-center gap-2 focus:outline-none"
126131
>
127-
<div
128-
v-tooltip.focus.right="getState?.toolTip"
129-
tabindex="0"
130-
:aria-label="getState?.toolTip"
131-
class="focus:outline-none"
132-
>
133-
<font-awesome-icon
134-
v-if="getState?.iconString"
135-
class="icon-detail"
136-
aria-hidden="true"
137-
:class="[getState?.iconClass]"
138-
:icon="getState?.iconString"
139-
/>
140-
<span class="text-color">
141-
{{ displayText ?? codeDisplay.PermitState?.[state] ?? state }}
142-
</span>
143-
</div>
132+
<font-awesome-icon
133+
v-if="getState?.iconString"
134+
class="icon-detail"
135+
aria-hidden="true"
136+
:class="[getState?.iconClass]"
137+
:icon="getState?.iconString"
138+
/>
139+
<span class="text-color">
140+
{{ displayText ?? codeDisplay.PermitState?.[state] ?? state }}
141+
</span>
144142
</div>
145143
</div>
146144
</template>
@@ -163,8 +161,7 @@ const { codeDisplay } = useCodeStore();
163161
}
164162
165163
.icon-detail {
166-
font-size: var(--icon-font-height);
167-
margin-right: 0.5rem;
164+
font-size: var(--icon-font-size);
168165
}
169166
170167
.green {

0 commit comments

Comments
 (0)