@reqquest/ui 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import type { CardSelectItem } from './FieldCardRadio.svelte'
2
+ import type { CardSelectItem } from '../components/FieldCardRadio.svelte'
3
3
  import { Card, CardGrid, FormInlineNotification } from '@txstate-mws/carbon-svelte'
4
4
  import { FORM_CONTEXT, FORM_INHERITED_PATH, Field, type FormStore } from '@txstate-mws/svelte-forms'
5
5
  import { Store } from '@txstate-mws/svelte-store'
@@ -1,12 +1,3 @@
1
- export { default as ApplicantProgramList } from './ApplicantProgramList.svelte';
2
- export { default as ApplicantPromptPage } from './ApplicantPromptPage.svelte';
3
- export { default as ApplicationDetailsView } from './ApplicationDetailsView.svelte';
4
- export { default as AppRequestCard } from './AppRequestCard.svelte';
5
- export { default as ButtonLoadingIcon } from './ButtonLoadingIcon.svelte';
6
- export { default as IntroPanel } from './IntroPanel.svelte';
7
- export { default as PeriodPanel } from './PeriodPanel.svelte';
8
- export { default as QuestionnairePrompt } from './QuestionnairePrompt.svelte';
9
- export { default as RenderDisplayComponent } from './RenderDisplayComponent.svelte';
10
- export { default as FieldCardRadio } from './FieldCardRadio.svelte';
11
1
  export { default as FieldCardCheckbox } from './FieldCardCheckbox.svelte';
12
- export * from './types.js';
2
+ export { default as FieldCardRadio } from './FieldCardRadio.svelte';
3
+ export { default as QuestionnairePrompt } from '../../lib/components/QuestionnairePrompt.svelte';
package/dist/index.js CHANGED
@@ -1,6 +1,4 @@
1
- export * from './registry.js';
2
- export * from './api.js';
3
1
  export * from './components/index.js';
2
+ export * from './registry.js';
3
+ export * from './types.js';
4
4
  export * from './typed-client/index.js';
5
- export * from './util.js';
6
- export * from './status-utils.js';
@@ -278,17 +278,6 @@ Represents a group of applications all being applied for at the same time. As pa
278
278
  type AppRequest {
279
279
  """Actions the user can take on this app request."""
280
280
  actions: AppRequestActions!
281
-
282
- """
283
- The activity log for this app request. This is a list of actions taken on the app request, such as submission, updating prompts, make an offer, add a note, etc. It will be sorted by the date of the activity in descending order.
284
- """
285
- activity(
286
- """
287
- Filters to apply to the activity log. This can be used to filter by action type, date range, etc.
288
- """
289
- filters: AppRequestActivityFilters
290
- paged: Pagination
291
- ): [AppRequestActivity!]!
292
281
  applicant: AccessUser!
293
282
  applications: [Application!]!
294
283
 
@@ -403,6 +392,16 @@ type AppRequestActions {
403
392
 
404
393
  """User may submit this app request either as or on behalf of the owner."""
405
394
  submit: Boolean!
395
+
396
+ """
397
+ User is able to see the acceptance UI. i.e. they are the applicant and the request is in the appropriate phase.
398
+ """
399
+ viewAcceptUI: Boolean!
400
+
401
+ """
402
+ User is able to see the applicant UI. i.e. they are the applicant and the request is in the appropriate phase.
403
+ """
404
+ viewApplyUI: Boolean!
406
405
  }
407
406
 
408
407
  type AppRequestActivity {
@@ -538,13 +537,23 @@ type AppRequestIndexCategory {
538
537
  If this is > 0, the index values should be shown on the applicant dashboard, sorted by this priority in descending order.
539
538
  """
540
539
  applicantDashboardPriority: Float
540
+
541
+ """
542
+ The internal category name for this index. Use this with any GraphQL filters.
543
+ """
541
544
  category: String!
545
+
546
+ """A human-friendly label for this category that can be shown in the UI."""
542
547
  categoryLabel: String!
543
548
 
544
549
  """
545
550
  If this is > 0, the index values should be shown on the list filters, sorted by this priority in descending order.
546
551
  """
547
552
  listFiltersPriority: Float
553
+
554
+ """
555
+ If true, this category has few enough values that it is reasonable to list them all in a dropdown or similar UI control. If false, the list of values is likely to get very long and it would be better to use an autofill combobox or something.
556
+ """
548
557
  listable: Boolean!
549
558
 
550
559
  """
@@ -960,13 +969,23 @@ type IndexCategory {
960
969
  If this is > 0, the index values should be shown on the applicant dashboard, sorted by this priority in descending order.
961
970
  """
962
971
  applicantDashboardPriority: Float
972
+
973
+ """
974
+ The internal category name for this index. Use this with any GraphQL filters.
975
+ """
963
976
  category: String!
977
+
978
+ """A human-friendly label for this category that can be shown in the UI."""
964
979
  categoryLabel: String!
965
980
 
966
981
  """
967
982
  If this is > 0, the index values should be shown on the list filters, sorted by this priority in descending order.
968
983
  """
969
984
  listFiltersPriority: Float
985
+
986
+ """
987
+ If true, this category has few enough values that it is reasonable to list them all in a dropdown or similar UI control. If false, the list of values is likely to get very long and it would be better to use an autofill combobox or something.
988
+ """
970
989
  listable: Boolean!
971
990
 
972
991
  """
@@ -1057,6 +1076,9 @@ type Mutation {
1057
1076
  """Create a new app request."""
1058
1077
  createAppRequest(login: String!, periodId: ID!, validateOnly: Boolean): ValidatedAppRequestResponse!
1059
1078
  createPeriod(copyPeriodId: String, period: PeriodUpdate!, validateOnly: Boolean): ValidatedPeriodResponse!
1079
+
1080
+ """Delete an existing note."""
1081
+ deleteNote(noteId: String!): Boolean!
1060
1082
  deletePeriod(periodId: ID!): ValidatedResponse!
1061
1083
  markPeriodReviewed(periodId: ID!, validateOnly: Boolean): ValidatedPeriodResponse!
1062
1084
 
@@ -1097,6 +1119,9 @@ type Mutation {
1097
1119
  """Submit the app request."""
1098
1120
  submitAppRequest(appRequestId: ID!): ValidatedAppRequestResponse!
1099
1121
  updateConfiguration(data: JsonData!, key: String!, periodId: ID!, validateOnly: Boolean): ValidatedConfigurationResponse!
1122
+
1123
+ """Update the content of an existing note."""
1124
+ updateNote(content: String!, noteId: String!): Note!
1100
1125
  updatePeriod(periodId: ID!, update: PeriodUpdate!, validateOnly: Boolean): ValidatedPeriodResponse!
1101
1126
  updatePeriodRequirement(disabled: Boolean!, periodId: String!, requirementKey: String!): ValidatedResponse!
1102
1127
 
@@ -1159,10 +1184,12 @@ type Note {
1159
1184
  content: String!
1160
1185
  createdAt: DateTime!
1161
1186
  id: ID!
1187
+ updatedAt: DateTime!
1162
1188
  }
1163
1189
 
1164
1190
  """Actions that can be performed on a note."""
1165
1191
  type NoteActions {
1192
+ delete: Boolean!
1166
1193
  update: Boolean!
1167
1194
  }
1168
1195
 
@@ -1426,6 +1453,18 @@ type Query {
1426
1453
  "\n This is the global access object. Each field represents a global permission\n like the ability to view the role management interface.\n "
1427
1454
  access: Access!
1428
1455
  accessUsers(filter: AccessUserFilter, paged: Pagination): [AccessUser!]!
1456
+
1457
+ """
1458
+ The activity log for this app request. This is a list of actions taken on the app request, such as submission, updating prompts, make an offer, add a note, etc. It will be sorted by the date of the activity in descending order.
1459
+ """
1460
+ appRequestActivity(
1461
+ """
1462
+ Filters to apply to the activity log. This can be used to filter by action type, date range, etc.
1463
+ """
1464
+ filters: AppRequestActivityFilters
1465
+ id: String!
1466
+ paged: Pagination
1467
+ ): [AppRequestActivity!]!
1429
1468
  appRequestIndexes(
1430
1469
  categories: [String!]
1431
1470
 
@@ -1449,6 +1488,12 @@ type Query {
1449
1488
  A list of all possible scopes. Scopes are used to limit users when they are accessing the system through an alternate UI or login method. For instance, if you generate an authentication token to give to a third party, it may have a scope identifying that third party and limiting their access even though they are acting as you. Roles must match the token scope in order to apply permissions.
1450
1489
  """
1451
1490
  scopes: [String!]!
1491
+ userIndexes(
1492
+ """
1493
+ Returns indexes that are flagged to appear in this destination. Also sorts for this destination.
1494
+ """
1495
+ for: AppRequestIndexDestination
1496
+ ): [IndexCategory!]!
1452
1497
  }
1453
1498
 
1454
1499
  """
@@ -405,17 +405,6 @@ export default {
405
405
  "actions": [
406
406
  23
407
407
  ],
408
- "activity": [
409
- 24,
410
- {
411
- "filters": [
412
- 25
413
- ],
414
- "paged": [
415
- 56
416
- ]
417
- }
418
- ],
419
408
  "applicant": [
420
409
  17
421
410
  ],
@@ -531,6 +520,12 @@ export default {
531
520
  "submit": [
532
521
  37
533
522
  ],
523
+ "viewAcceptUI": [
524
+ 37
525
+ ],
526
+ "viewApplyUI": [
527
+ 37
528
+ ],
534
529
  "__typename": [
535
530
  77
536
531
  ]
@@ -1038,6 +1033,15 @@ export default {
1038
1033
  ]
1039
1034
  }
1040
1035
  ],
1036
+ "deleteNote": [
1037
+ 37,
1038
+ {
1039
+ "noteId": [
1040
+ 77,
1041
+ "String!"
1042
+ ]
1043
+ }
1044
+ ],
1041
1045
  "deletePeriod": [
1042
1046
  81,
1043
1047
  {
@@ -1223,6 +1227,19 @@ export default {
1223
1227
  ]
1224
1228
  }
1225
1229
  ],
1230
+ "updateNote": [
1231
+ 54,
1232
+ {
1233
+ "content": [
1234
+ 77,
1235
+ "String!"
1236
+ ],
1237
+ "noteId": [
1238
+ 77,
1239
+ "String!"
1240
+ ]
1241
+ }
1242
+ ],
1226
1243
  "updatePeriod": [
1227
1244
  80,
1228
1245
  {
@@ -1313,11 +1330,17 @@ export default {
1313
1330
  "id": [
1314
1331
  45
1315
1332
  ],
1333
+ "updatedAt": [
1334
+ 43
1335
+ ],
1316
1336
  "__typename": [
1317
1337
  77
1318
1338
  ]
1319
1339
  },
1320
1340
  "NoteActions": {
1341
+ "delete": [
1342
+ 37
1343
+ ],
1321
1344
  "update": [
1322
1345
  37
1323
1346
  ],
@@ -1623,6 +1646,21 @@ export default {
1623
1646
  ]
1624
1647
  }
1625
1648
  ],
1649
+ "appRequestActivity": [
1650
+ 24,
1651
+ {
1652
+ "filters": [
1653
+ 25
1654
+ ],
1655
+ "id": [
1656
+ 77,
1657
+ "String!"
1658
+ ],
1659
+ "paged": [
1660
+ 56
1661
+ ]
1662
+ }
1663
+ ],
1626
1664
  "appRequestIndexes": [
1627
1665
  46,
1628
1666
  {
@@ -1679,6 +1717,14 @@ export default {
1679
1717
  "scopes": [
1680
1718
  77
1681
1719
  ],
1720
+ "userIndexes": [
1721
+ 46,
1722
+ {
1723
+ "for": [
1724
+ 28
1725
+ ]
1726
+ }
1727
+ ],
1682
1728
  "__typename": [
1683
1729
  77
1684
1730
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reqquest/ui",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "exports": {
5
5
  ".": {
6
6
  "types": "./dist/index.d.ts",
@@ -23,14 +23,14 @@
23
23
  },
24
24
  "peerDependencies": {
25
25
  "@sveltejs/kit": "^2.0.0",
26
- "svelte": "^4.2.15 || ^5.0.0"
26
+ "svelte": "^5.0.0"
27
27
  },
28
28
  "dependencies": {
29
29
  "@txstate-mws/carbon-svelte": "^1.5.5",
30
30
  "@txstate-mws/fastify-shared": "^1.1.0",
31
31
  "@txstate-mws/svelte-components": "^1.6.11",
32
32
  "@txstate-mws/sveltekit-utils": "^1.0.2",
33
- "carbon-components-svelte": ">=0.85.1 <1",
33
+ "carbon-components-svelte": ">=0.85.1 <0.96.0",
34
34
  "carbon-icons-svelte": "^13.0.0",
35
35
  "luxon": "^3.5.0",
36
36
  "txstate-utils": "^1.8.15"
@@ -1,172 +0,0 @@
1
- <script lang="ts">
2
- import { goto } from '$app/navigation'
3
- import { resolve } from '$app/paths'
4
- import { getApplicationStatusInfo, getAppRequestStatusInfo, getNavigationButton } from '../status-utils.js'
5
- import { longNumericTime } from '../util.js'
6
- import type { ActionItem } from '@txstate-mws/carbon-svelte'
7
- import { Card, TagSet } from '@txstate-mws/carbon-svelte'
8
- import Button from "carbon-components-svelte/src/Button/Button.svelte";
9
- import type { PageData } from '../../routes/dashboards/applicant/$types'
10
- import StatusMessageList from './StatusMessageList.svelte'
11
- import WarningIconYellow from './WarningIconYellow.svelte'
12
- import { enumPromptVisibility } from '../typed-client'
13
-
14
- // Type for the partial AppRequest data passed from dashboard
15
- type DashboardAppRequest = PageData['appRequests'][number]
16
-
17
- export let request: DashboardAppRequest
18
- export let actions: ActionItem[] = []
19
- export let showAcceptanceButtons = true
20
- export let onAcceptanceNavigate: ((requestId: string) => void) | undefined = undefined
21
-
22
- $: statusInfo = getAppRequestStatusInfo(request.status)
23
- $: firstInvalidatedPrompt = request.applications
24
- .flatMap(app => app.requirements)
25
- .flatMap(req => req.prompts)
26
- .find(p => p.visibility === enumPromptVisibility.AVAILABLE && p.invalidated && p.invalidatedReason)
27
- $: navButton = firstInvalidatedPrompt
28
- ? { label: 'Make corrections', href: `/requests/${request.id}/apply/${firstInvalidatedPrompt.id}` }
29
- : getNavigationButton(request.status, request.id)
30
-
31
- async function handleAcceptanceClick () {
32
- if (onAcceptanceNavigate) {
33
- onAcceptanceNavigate(request.id)
34
- } else {
35
- await goto(resolve(`/requests/${request.id}/apply`))
36
- }
37
- }
38
- </script>
39
-
40
- <Card
41
- title={request.period.name}
42
- subhead={`Started: ${longNumericTime(request.createdAt)}`}
43
- tags={[{ label: statusInfo.label, type: statusInfo.color }]}
44
- tagsInBody
45
- {actions}
46
- forceOverflow={true}
47
- navigations={navButton ? [navButton] : []}>
48
-
49
- <!-- Status description -->
50
- {#if statusInfo.description}
51
- <p class="pl-1.5 mb-4 text-sm">{statusInfo.description}</p>
52
- {/if}
53
-
54
- <!-- Benefits section -->
55
- <div class="rounded">
56
- <h4 class="m-0 mb-2 text-lg benefits-title">Potential benefits</h4>
57
- <p class="m-0 mb-3 benefits-subtitle text-sm">Benefit results will be finalized once the application submission and review is completed.</p>
58
-
59
- {#if request.applications.length > 0}
60
- {#each request.applications as application (application.id)}
61
- {@const invalidatedPrompts = application.requirements
62
- .flatMap(req => req.prompts)
63
- .filter(p => p.visibility === enumPromptVisibility.AVAILABLE && p.invalidated && p.invalidatedReason)
64
- }
65
- {@const warningReqs = application.requirements.filter(r => r.status === 'WARNING' && r.statusReason)}
66
- {@const appStatusTag = invalidatedPrompts.length > 0
67
- ? { label: 'Needs corrections', color: 'magenta' as const }
68
- : getApplicationStatusInfo(application.status)}
69
- <div class="program-status py-2 px-4 mb-4">
70
- <div class="flex items-center">
71
- <span class="font-medium">{application.title}</span>
72
- <div class="tagwrap">
73
- <TagSet tags={[{ label: appStatusTag.label, type: appStatusTag.color }]} />
74
- </div>
75
- {#if (application.status === 'PENDING' || application.status === 'ELIGIBLE') && warningReqs.length > 0}
76
- <WarningIconYellow size={20} />
77
- {/if}
78
-
79
- <!-- Acceptance buttons -->
80
- {#if showAcceptanceButtons && (request.status === 'ACCEPTANCE' || request.status === 'READY_TO_ACCEPT') && application.status === 'ELIGIBLE'}
81
- <Button kind="primary" size="small" class="ml-auto"
82
- on:click={handleAcceptanceClick}>
83
- {request.status === 'READY_TO_ACCEPT' ? 'Accept Offer' : 'Review Offer'}
84
- </Button>
85
- {/if}
86
- </div>
87
-
88
- <!-- Status reason -->
89
- {#if application.statusReason && application.status !== 'INELIGIBLE' && invalidatedPrompts.length === 0}
90
- <p class="status-reason mt-2 mb-0 text-sm">{application.statusReason}</p>
91
- {/if}
92
-
93
- <!-- Warnings for PENDING/ELIGIBLE applications -->
94
- {#if (application.status === 'PENDING' || application.status === 'ELIGIBLE') && warningReqs.length > 0}
95
- <StatusMessageList
96
- items={warningReqs.map(r => ({ id: r.id, message: r.statusReason! }))}
97
- variant="warning"
98
- accordionTitle="Multiple warnings" />
99
- {/if}
100
-
101
- <!-- Failed requirements for INELIGIBLE applications -->
102
- {#if application.status === 'INELIGIBLE' && application.requirements}
103
- {@const failedRequirements = application.requirements.filter(req => req.status === 'DISQUALIFYING' && req.statusReason)}
104
- <StatusMessageList
105
- items={failedRequirements.map(r => ({ id: r.id, message: r.statusReason! }))}
106
- accordionTitle="Multiple eligibility issues" />
107
- {/if}
108
-
109
- <!-- Corrections needed for non-INELIGIBLE applications -->
110
- {#if invalidatedPrompts.length > 0}
111
- <StatusMessageList
112
- items={invalidatedPrompts.map(p => ({ id: p.id, message: p.invalidatedReason! }))}
113
- accordionTitle="Multiple corrections needed" />
114
- {/if}
115
- </div>
116
- {/each}
117
- {:else}
118
- <p>No benefits associated with this application.</p>
119
- {/if}
120
- </div>
121
-
122
- <!-- Footer info grid -->
123
- <div class="mt-4 grid grid-cols-3 footer-grid">
124
- <div class="text-center py-4 px-2 footer-section">
125
- <span class="block text-sm font-semibold footer-label mb-1">Request number:</span>
126
- <span class="block text-sm footer-value">{request.id.slice(0, 6).toUpperCase()}</span>
127
- </div>
128
- <div class="text-center py-4 px-2 footer-section">
129
- <span class="block text-sm font-semibold footer-label mb-1">Last updated:</span>
130
- <span class="block text-sm footer-value">{longNumericTime(request.updatedAt)}</span>
131
- </div>
132
- <div class="text-center py-4 px-2 footer-section">
133
- <span class="block text-sm font-semibold footer-label mb-1">Waiting on:</span>
134
- <span class="block text-sm footer-value">{statusInfo.waitingOn}</span>
135
- </div>
136
- </div>
137
- </Card>
138
-
139
- <style>
140
- /* Global styles for external component overrides */
141
- :global(.tagwrap .tag-set > *) {
142
- max-width: 100% !important;
143
- }
144
-
145
- .benefits-subtitle {
146
- color: var(--cds-text-02);
147
- }
148
-
149
- .program-status {
150
- background-color: var(--cds-ui-01);
151
- }
152
-
153
- .footer-grid {
154
- background-color: var(--cds-ui-01);
155
- }
156
-
157
- .footer-section {
158
- border-right: 1px solid var(--cds-ui-05);
159
-
160
- }
161
- .footer-section:last-child {
162
- border-right: none;
163
- }
164
-
165
- .footer-label {
166
- color: var(--cds-text-01);
167
- }
168
-
169
- .footer-value {
170
- color: var(--cds-text-01);
171
- }
172
- </style>
@@ -1,184 +0,0 @@
1
- <script lang="ts">
2
- import { TagSet } from '@txstate-mws/carbon-svelte'
3
- import Button from "carbon-components-svelte/src/Button/Button.svelte";
4
- import Close from "carbon-icons-svelte/lib/Close.svelte";
5
- import InProgress from "carbon-icons-svelte/lib/InProgress.svelte";
6
- import CheckmarkFilled from "carbon-icons-svelte/lib/CheckmarkFilled.svelte";
7
- import Information from "carbon-icons-svelte/lib/Information.svelte";
8
- import { ucfirst } from 'txstate-utils'
9
- import type { ApplicationForDetails } from './types'
10
- import { enumApplicationStatus, enumIneligiblePhases, enumRequirementType, getApplicationStatusInfo } from '..'
11
- import ApplicantProgramListTooltip from './ApplicantProgramListTooltip.svelte'
12
- import WarningIconYellow from './WarningIconYellow.svelte'
13
-
14
- export let applications: ApplicationForDetails[]
15
- export let viewMode = false
16
- export let showTooltipsAsText = false
17
-
18
- $: promptsByApplicationId = applications.reduce<Record<string, typeof applications[0]['requirements'][0]['prompts'] | undefined>>((acc, curr) => ({
19
- ...acc,
20
- [curr.id]: curr.requirements
21
- .filter(r => r.type === enumRequirementType.QUALIFICATION)
22
- .flatMap(r => r.prompts)
23
- }), {})
24
-
25
- $: programButtonStatus = applications.reduce((acc, curr) => ({
26
- ...acc,
27
- [curr.id]: curr.completionStatus === enumApplicationStatus.PENDING
28
- ? curr.requirements.some(r => r.prompts.some(p => p.answered && !p.invalidated))
29
- ? curr.requirements.filter(r => r.type === enumRequirementType.QUALIFICATION).every(r => r.prompts.every(p => p.answered && !p.invalidated))
30
- ? 'complete'
31
- : 'continue'
32
- : 'start'
33
- : curr.completionStatus === enumApplicationStatus.INELIGIBLE
34
- ? curr.ineligiblePhase === enumIneligiblePhases.PREQUAL
35
- ? 'ineligible'
36
- : 'revisit'
37
- : 'complete'
38
- }), {})
39
- $: programFirstPromptId = applications.reduce((acc, curr) => ({
40
- ...acc,
41
- [curr.id]: (promptsByApplicationId[curr.id]?.find(p => !p.answered || p.invalidated) ?? promptsByApplicationId[curr.id]?.[0])?.id
42
- }), {})
43
- </script>
44
-
45
- <section class="programs-container">
46
- <header>
47
- <div class="program column">Program</div>
48
- <div class="status column">Eligibility</div>
49
- </header>
50
- {#each applications as application (application.id)}
51
- {@const programStatus = programButtonStatus[application.id]}
52
- {@const programFirstPrompt = programFirstPromptId[application.id]}
53
- <div class="program column">{application.title}</div>
54
- <div class="status column" class:no-tooltip={!application.statusReason?.length}>
55
- {#if !viewMode}
56
- <div class="icon-and-tooltip" class:wide-icon={application.completionStatus === enumApplicationStatus.INELIGIBLE}>
57
- {#if application.completionStatus === enumApplicationStatus.INELIGIBLE}
58
- <Close size={32} class="status-icon-ineligible" />
59
- {:else if ['start', 'continue'].includes(programStatus)}
60
- <InProgress size={24} class="status-icon-pending" />
61
- {:else if application.hasWarning}
62
- <WarningIconYellow size={24} class="status-icon-warning" />
63
- {:else}
64
- <CheckmarkFilled size={24} class="status-icon-complete" />
65
- {/if}
66
- <ApplicantProgramListTooltip {application} />
67
- </div>
68
- {#if programFirstPrompt && programStatus !== 'ineligible'}
69
- <Button size="small" kind={programStatus === 'complete' ? 'ghost' : programStatus === 'revisit' ? 'secondary' : 'primary'} href={programFirstPrompt}>{ucfirst(programStatus)}</Button>
70
- {/if}
71
- {:else}
72
- {@const statusInfo = getApplicationStatusInfo(application.status)}
73
- <TagSet tags={[{ type: statusInfo.color, label: statusInfo.label }]} />
74
- <ApplicantProgramListTooltip {application} />
75
- {/if}
76
- </div>
77
- {#if application.warningReasons.length || application.ineligibleReasons.length}
78
- <div class="tooltip-text-row" class:visible={showTooltipsAsText}>
79
- {#each application.ineligibleReasons as reason (reason)}
80
- <div class="tooltip-text-item">
81
- <Information size={16} /> {reason}
82
- </div>
83
- {/each}
84
- {#each application.warningReasons as reason (reason)}
85
- <div class="tooltip-text-item">
86
- <Information size={16} /> {reason}
87
- </div>
88
- {/each}
89
- </div>
90
- {/if}
91
- {/each}
92
- </section>
93
-
94
- <style>
95
- .programs-container {
96
- display: grid;
97
- grid-template-columns: 2fr 1fr;
98
- margin-bottom: 1.5rem;
99
- }
100
-
101
- .programs-container header {
102
- display: contents;
103
- font-weight: bold;
104
- }
105
-
106
- .programs-container header .column {
107
- padding: 0.5rem 8px;
108
- }
109
-
110
- .programs-container .column {
111
- border-bottom: 1px solid var(--cds-ui-03, #e0e0e0);
112
- padding: 1rem 8px;
113
- }
114
-
115
- .programs-container :global(.status-column) {
116
- flex-grow: 0;
117
- }
118
-
119
- :not(.header) .program.column {
120
- display: flex;
121
- align-items: center;
122
- }
123
-
124
- :not(.header) .status.column {
125
- display: flex;
126
- flex-wrap: wrap;
127
- align-items: center;
128
- justify-content: flex-start;
129
- gap: 12px;
130
- }
131
-
132
- .status.column :global(.reason-tooltip) {
133
- height: 16px;
134
- }
135
- :not(.header) .status.column.no-tooltip {
136
- flex-wrap: nowrap
137
- }
138
-
139
- .programs-container :global(.status-icon-pending) {
140
- fill: var(--cds-support-04);
141
- }
142
-
143
- .programs-container :global(.status-icon-complete) {
144
- fill: var(--cds-support-04);
145
- }
146
-
147
- .programs-container :global(.status-icon-ineligible) {
148
- margin-left: -4px;
149
- }
150
-
151
- .icon-and-tooltip {
152
- display: flex;
153
- align-items: center;
154
- gap: 8px;
155
- }
156
- .icon-and-tooltip.wide-icon {
157
- gap: 4px;
158
- }
159
-
160
- .tooltip-text-row {
161
- grid-column: span 2;
162
- background-color: #FBF1DA;
163
- padding: 0.5rem 1rem;
164
- display: none;
165
- }
166
-
167
- .tooltip-text-row.visible {
168
- display: block;
169
- }
170
-
171
- .tooltip-text-item {
172
- display: flex;
173
- align-items: center;
174
- gap: 0.5rem;
175
- padding: 0.125rem 16px;
176
- color: var(--cds-text-01);
177
- }
178
-
179
- @media print {
180
- .tooltip-text-row {
181
- display: block !important;
182
- }
183
- }
184
- </style>