@reqquest/ui 1.1.1 → 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.
- package/dist/api.js +1 -1159
- package/dist/components/FieldCardCheckbox.svelte +1 -1
- package/dist/components/index.js +2 -11
- package/dist/index.js +2 -4
- package/package.json +2 -2
- package/dist/components/AppRequestCard.svelte +0 -172
- package/dist/components/ApplicantProgramList.svelte +0 -184
- package/dist/components/ApplicantProgramListTooltip.svelte +0 -22
- package/dist/components/ApplicantPromptPage.svelte +0 -88
- package/dist/components/ApplicationDetailsView.svelte +0 -307
- package/dist/components/ButtonLoadingIcon.svelte +0 -28
- package/dist/components/IntroPanel.svelte +0 -41
- package/dist/components/PeriodPanel.svelte +0 -100
- package/dist/components/RenderDisplayComponent.svelte +0 -38
- package/dist/components/ReviewerList.svelte +0 -93
- package/dist/components/StatusMessageList.svelte +0 -35
- package/dist/components/WarningIconYellow.svelte +0 -20
- package/dist/csv.js +0 -21
- package/dist/status-utils.js +0 -343
- package/dist/stores/IStateStore.js +0 -0
- package/dist/util.js +0 -14
- /package/dist/{components/types.js → types.js} +0 -0
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { UIRegistry } from '../registry.js'
|
|
3
|
-
import { getAppRequestStatusInfo, getApplicationStatusInfo, applicantRequirementTypes, reviewRequirementTypes } from '../status-utils.js'
|
|
4
|
-
import type { Scalars } from '../typed-client/schema'
|
|
5
|
-
import { enumRequirementType, type RequirementType } from '../typed-client/index.js'
|
|
6
|
-
import { Panel, TagSet } from '@txstate-mws/carbon-svelte'
|
|
7
|
-
import Button from "carbon-components-svelte/src/Button/Button.svelte";
|
|
8
|
-
import InlineNotification from "carbon-components-svelte/src/Notification/InlineNotification.svelte";
|
|
9
|
-
import Tooltip from "carbon-components-svelte/src/Tooltip/Tooltip.svelte";
|
|
10
|
-
import Edit from 'carbon-icons-svelte/lib/Edit.svelte'
|
|
11
|
-
import type { AnsweredPrompt, PromptSection, AppRequestForDetails, ApplicationForDetails } from './types'
|
|
12
|
-
import RenderDisplayComponent from './RenderDisplayComponent.svelte'
|
|
13
|
-
import ApplicantProgramList from './ApplicantProgramList.svelte'
|
|
14
|
-
import WarningIconYellow from './WarningIconYellow.svelte'
|
|
15
|
-
|
|
16
|
-
// TODO: design alignement could reduce props here
|
|
17
|
-
export let appRequest: AppRequestForDetails
|
|
18
|
-
export let applications: ApplicationForDetails[]
|
|
19
|
-
export let appData: Scalars['JsonData'] = {}
|
|
20
|
-
export let prequalPrompts: AnsweredPrompt[] | undefined = undefined
|
|
21
|
-
export let postqualPrompts: AnsweredPrompt[] | undefined = undefined
|
|
22
|
-
export let loading = false
|
|
23
|
-
export let uiRegistry: UIRegistry
|
|
24
|
-
export let title = 'View your application'
|
|
25
|
-
export let subtitle = 'Select document names to preview them.'
|
|
26
|
-
export let expandable = true
|
|
27
|
-
export let showWarningsInline = false
|
|
28
|
-
export let showCorrectionsInline = false
|
|
29
|
-
export let showAppRequestStatus = true
|
|
30
|
-
export let statusDisplay: 'tags' | 'icons' = 'tags'
|
|
31
|
-
export let showTooltipsAsText = false
|
|
32
|
-
|
|
33
|
-
const CORRECTABLE_STATUSES = ['STARTED', 'READY_TO_SUBMIT', 'DISQUALIFIED']
|
|
34
|
-
|
|
35
|
-
$: canMakeCorrections = CORRECTABLE_STATUSES.includes(appRequest.status)
|
|
36
|
-
|
|
37
|
-
// Group prompts by sections, with reviewer prompts nested within application sections
|
|
38
|
-
$: sections = (() => {
|
|
39
|
-
const sections: PromptSection[] = []
|
|
40
|
-
|
|
41
|
-
// General Questions === PREQUAL prompts
|
|
42
|
-
if (prequalPrompts?.length) {
|
|
43
|
-
sections.push({ title: 'General Questions', prompts: prequalPrompts })
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Application-Specific Questions with nested Reviewer Questions
|
|
47
|
-
for (const application of applications) {
|
|
48
|
-
const applicantPrompts = application.requirements
|
|
49
|
-
.filter(r => applicantRequirementTypes.has(r.type))
|
|
50
|
-
.flatMap(r => r.prompts)
|
|
51
|
-
const reviewerPrompts = application.requirements
|
|
52
|
-
.filter(r => reviewRequirementTypes.has(r.type))
|
|
53
|
-
.flatMap(r => r.prompts)
|
|
54
|
-
const workflowPrompts = application.requirements
|
|
55
|
-
.filter(r => r.type === enumRequirementType.WORKFLOW)
|
|
56
|
-
.flatMap(r => r.prompts)
|
|
57
|
-
|
|
58
|
-
if (applicantPrompts.length || reviewerPrompts.length || workflowPrompts.length) {
|
|
59
|
-
const subsections: PromptSection[] = []
|
|
60
|
-
if (reviewerPrompts.length) subsections.push({ title: 'Reviewer Questions', prompts: reviewerPrompts })
|
|
61
|
-
if (workflowPrompts.length) subsections.push({ title: 'Workflow Questions', prompts: workflowPrompts })
|
|
62
|
-
sections.push({
|
|
63
|
-
title: application.title,
|
|
64
|
-
prompts: applicantPrompts,
|
|
65
|
-
subsections,
|
|
66
|
-
applicationStatus: application.status
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Additional Questions === POSTQUAL prompts
|
|
72
|
-
if (postqualPrompts?.length) {
|
|
73
|
-
sections.push({ title: 'Additional Questions', prompts: postqualPrompts })
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return sections
|
|
77
|
-
})()
|
|
78
|
-
|
|
79
|
-
function hasWarning (prompt: AnsweredPrompt) {
|
|
80
|
-
return prompt.statusReasons.some(r => r.status === 'WARNING' || r.status === 'DISQUALIFYING')
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function getWarnings (prompt: AnsweredPrompt) {
|
|
84
|
-
return prompt.statusReasons.filter(r => r.status === 'WARNING' || r.status === 'DISQUALIFYING')
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function needsCorrection (prompt: AnsweredPrompt) {
|
|
88
|
-
return prompt.invalidated && prompt.invalidatedReason
|
|
89
|
-
}
|
|
90
|
-
</script>
|
|
91
|
-
|
|
92
|
-
{#if appRequest}
|
|
93
|
-
<div class="[ my-6 ] application-details flow">
|
|
94
|
-
<!-- Application Status Panel -->
|
|
95
|
-
<header class="[ mb-12 ] app-view-intro text-center">
|
|
96
|
-
<h2 class="[ text-xl mb-3 ]">{title}</h2>
|
|
97
|
-
<p class="app-view-subtitle mb-3">{subtitle}</p>
|
|
98
|
-
</header>
|
|
99
|
-
<section class="prompt-section">
|
|
100
|
-
<div class="status-content">
|
|
101
|
-
{#if showAppRequestStatus}
|
|
102
|
-
<dl class="status-list-item [ flex items-center justify-between px-2 py-3 border-b ]">
|
|
103
|
-
<dt class="status-list-label font-medium">Application Status</dt>
|
|
104
|
-
<dd class="px-2">
|
|
105
|
-
<TagSet tags={[{ label: getAppRequestStatusInfo(appRequest.status).label, type: getAppRequestStatusInfo(appRequest.status).color }]} />
|
|
106
|
-
</dd>
|
|
107
|
-
</dl>
|
|
108
|
-
{/if}
|
|
109
|
-
|
|
110
|
-
<!-- Application Status List -->
|
|
111
|
-
<ApplicantProgramList {applications} viewMode={statusDisplay === 'tags'} {showTooltipsAsText} />
|
|
112
|
-
</div>
|
|
113
|
-
</section>
|
|
114
|
-
|
|
115
|
-
<!-- Prompt Sections -->
|
|
116
|
-
{#if loading}
|
|
117
|
-
<Panel title="Loading...">
|
|
118
|
-
<p>Loading prompt data...</p>
|
|
119
|
-
</Panel>
|
|
120
|
-
{:else if sections.length > 0}
|
|
121
|
-
{#each sections as section (section.title)}
|
|
122
|
-
<Panel title={section.title} {expandable} expanded>
|
|
123
|
-
<svelte:fragment slot="headerLeft">
|
|
124
|
-
{#if section.applicationStatus}
|
|
125
|
-
<TagSet tags={[{ label: getApplicationStatusInfo(section.applicationStatus).label, type: getApplicationStatusInfo(section.applicationStatus).color }]} />
|
|
126
|
-
{/if}
|
|
127
|
-
</svelte:fragment>
|
|
128
|
-
{#if section.prompts.length}
|
|
129
|
-
<dl class="prompt-list">
|
|
130
|
-
{#each section.prompts as prompt (prompt.id)}
|
|
131
|
-
{@const def = uiRegistry.getPrompt(prompt.key)}
|
|
132
|
-
<dt class="prompt-term [ font-medium ]">
|
|
133
|
-
{#if showWarningsInline && hasWarning(prompt)}
|
|
134
|
-
<Tooltip align="start">
|
|
135
|
-
<div class="icon" slot="icon">
|
|
136
|
-
<WarningIconYellow size={16} />
|
|
137
|
-
</div>
|
|
138
|
-
{#each getWarnings(prompt) as r, i (i)}
|
|
139
|
-
<p>
|
|
140
|
-
{r.status === 'WARNING' ? 'Warning' : 'Disqualifying'}{#if section.title !== r.programName} for {r.programName}{/if}<br>
|
|
141
|
-
{r.statusReason}
|
|
142
|
-
</p>
|
|
143
|
-
{/each}
|
|
144
|
-
</Tooltip>
|
|
145
|
-
{/if}
|
|
146
|
-
{#if showCorrectionsInline && canMakeCorrections && needsCorrection(prompt)}
|
|
147
|
-
<Tooltip align="start">
|
|
148
|
-
<div class="icon" slot="icon">
|
|
149
|
-
<WarningIconYellow size={16} />
|
|
150
|
-
</div>
|
|
151
|
-
<p>Correction needed<br>{prompt.invalidatedReason}</p>
|
|
152
|
-
</Tooltip>
|
|
153
|
-
{/if}
|
|
154
|
-
{prompt.title}
|
|
155
|
-
</dt>
|
|
156
|
-
<dd class="prompt-answer flow" class:large={def?.displayMode === 'large'}>
|
|
157
|
-
<RenderDisplayComponent {def} appRequestId={appRequest.id} appData={appData} prompt={prompt} configData={prompt.configurationData} gatheredConfigData={prompt.gatheredConfigData} />
|
|
158
|
-
{#if showCorrectionsInline && canMakeCorrections && needsCorrection(prompt)}
|
|
159
|
-
<Button kind="ghost" size="small" icon={Edit} iconDescription="Edit this answer" href={`/requests/${appRequest.id}/apply/${prompt.id}`} class="edit-button" />
|
|
160
|
-
{/if}
|
|
161
|
-
</dd>
|
|
162
|
-
{#if showCorrectionsInline && canMakeCorrections && needsCorrection(prompt)}
|
|
163
|
-
<div class="correction-notice">
|
|
164
|
-
<InlineNotification kind="warning-alt" title="Correction needed" subtitle={prompt.invalidatedReason ?? ''} hideCloseButton lowContrast />
|
|
165
|
-
</div>
|
|
166
|
-
{/if}
|
|
167
|
-
{/each}
|
|
168
|
-
</dl>
|
|
169
|
-
{/if}
|
|
170
|
-
|
|
171
|
-
<!-- Nested subsections (e.g., Reviewer Questions) -->
|
|
172
|
-
{#if section.subsections}
|
|
173
|
-
{#each section.subsections as subsection (subsection.title)}
|
|
174
|
-
<Panel title={subsection.title} {expandable} expanded>
|
|
175
|
-
<dl class="prompt-list">
|
|
176
|
-
{#each subsection.prompts as prompt (prompt.id)}
|
|
177
|
-
{@const def = uiRegistry.getPrompt(prompt.key)}
|
|
178
|
-
<dt class="prompt-term [ font-medium ]">
|
|
179
|
-
{#if showWarningsInline && hasWarning(prompt)}
|
|
180
|
-
<Tooltip align="start">
|
|
181
|
-
<div class="icon" slot="icon">
|
|
182
|
-
<WarningIconYellow size={16} />
|
|
183
|
-
</div>
|
|
184
|
-
{#each getWarnings(prompt) as r, i (i)}
|
|
185
|
-
<p>
|
|
186
|
-
{r.status === 'WARNING' ? 'Warning' : 'Disqualifying'}{#if section.title !== r.programName} for {r.programName}{/if}<br>
|
|
187
|
-
{r.statusReason}
|
|
188
|
-
</p>
|
|
189
|
-
{/each}
|
|
190
|
-
</Tooltip>
|
|
191
|
-
{/if}
|
|
192
|
-
{#if showCorrectionsInline && canMakeCorrections && needsCorrection(prompt)}
|
|
193
|
-
<Tooltip align="start">
|
|
194
|
-
<div class="icon" slot="icon">
|
|
195
|
-
<WarningIconYellow size={16} />
|
|
196
|
-
</div>
|
|
197
|
-
<p>Correction needed<br>{prompt.invalidatedReason}</p>
|
|
198
|
-
</Tooltip>
|
|
199
|
-
{/if}
|
|
200
|
-
{prompt.title}
|
|
201
|
-
</dt>
|
|
202
|
-
<dd class="prompt-answer flow" class:large={def?.displayMode === 'large'}>
|
|
203
|
-
<RenderDisplayComponent {def} appRequestId={appRequest.id} appData={appData} prompt={prompt} configData={prompt.configurationData} gatheredConfigData={prompt.gatheredConfigData} />
|
|
204
|
-
{#if showCorrectionsInline && canMakeCorrections && needsCorrection(prompt)}
|
|
205
|
-
<Button kind="ghost" size="small" icon={Edit} iconDescription="Edit this answer" href={`/requests/${appRequest.id}/apply/${prompt.id}`} class="edit-button" />
|
|
206
|
-
{/if}
|
|
207
|
-
</dd>
|
|
208
|
-
{#if showCorrectionsInline && canMakeCorrections && needsCorrection(prompt)}
|
|
209
|
-
<div class="correction-notice">
|
|
210
|
-
<InlineNotification kind="warning-alt" title="Correction needed" subtitle={prompt.invalidatedReason ?? ''} hideCloseButton lowContrast />
|
|
211
|
-
</div>
|
|
212
|
-
{/if}
|
|
213
|
-
{/each}
|
|
214
|
-
</dl>
|
|
215
|
-
</Panel>
|
|
216
|
-
{/each}
|
|
217
|
-
{/if}
|
|
218
|
-
</Panel>
|
|
219
|
-
{/each}
|
|
220
|
-
{:else}
|
|
221
|
-
<Panel title="Prompts and Answers">
|
|
222
|
-
<p>No prompts available for this application.</p>
|
|
223
|
-
</Panel>
|
|
224
|
-
{/if}
|
|
225
|
-
|
|
226
|
-
<slot name="footer" />
|
|
227
|
-
</div>
|
|
228
|
-
{:else}
|
|
229
|
-
<p>No application selected</p>
|
|
230
|
-
{/if}
|
|
231
|
-
|
|
232
|
-
<style>
|
|
233
|
-
.app-view-subtitle {
|
|
234
|
-
color: var(--cds-text-02);
|
|
235
|
-
/* margin-top: -0.5rem; */
|
|
236
|
-
margin-bottom: 1rem;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
.status-list-item {
|
|
240
|
-
border-bottom: 1px solid var(--cds-border-subtle);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
.prompt-answer :global(dl) {
|
|
244
|
-
padding-block-start:1em;
|
|
245
|
-
display:grid;
|
|
246
|
-
grid-template-columns: 1fr 1fr;
|
|
247
|
-
row-gap:0.5rem;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
.status-content dl {
|
|
251
|
-
padding-block-start:1em;
|
|
252
|
-
display:grid;
|
|
253
|
-
grid-template-columns: 2fr 1fr;
|
|
254
|
-
row-gap:0.5rem;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
.status-list-item {
|
|
258
|
-
border-color: var(--cds-border-subtle);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
.status-list-label {
|
|
262
|
-
color: var(--cds-text-01);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
.prompt-list {
|
|
266
|
-
display: grid;
|
|
267
|
-
grid-template-columns: 1fr 1fr;
|
|
268
|
-
align-items: stretch;
|
|
269
|
-
row-gap: 0.5rem;
|
|
270
|
-
}
|
|
271
|
-
.prompt-list dt, .prompt-list dd {
|
|
272
|
-
padding-bottom: 0.5rem;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
.prompt-term {
|
|
276
|
-
display: flex;
|
|
277
|
-
gap:1em;
|
|
278
|
-
color: var(--cds-text-01);
|
|
279
|
-
border-bottom: 1px solid var(--cds-border-subtle);
|
|
280
|
-
}
|
|
281
|
-
.prompt-term:has(+ .prompt-answer.large) {
|
|
282
|
-
border-bottom: none;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
.prompt-answer {
|
|
286
|
-
color: var(--cds-text-02);
|
|
287
|
-
border-bottom: 1px solid var(--cds-border-subtle);
|
|
288
|
-
}
|
|
289
|
-
.prompt-answer.large {
|
|
290
|
-
grid-column: span 2;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
.correction-notice {
|
|
294
|
-
grid-column: span 2;
|
|
295
|
-
margin-bottom: 0.5rem;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
.correction-notice :global(.bx--inline-notification) {
|
|
299
|
-
max-width: 100%;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
.prompt-answer :global(.edit-button) {
|
|
303
|
-
float: right;
|
|
304
|
-
margin-top: -0.5rem;
|
|
305
|
-
--cds-icon-01: var(--cds-link-01);
|
|
306
|
-
}
|
|
307
|
-
</style>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { ScreenReaderOnly } from '@txstate-mws/svelte-components'
|
|
3
|
-
</script>
|
|
4
|
-
|
|
5
|
-
<svg style:display="none"></svg>
|
|
6
|
-
<span {...$$restProps} class="{$$restProps.class} loader" aria-hidden="false"><ScreenReaderOnly>loading</ScreenReaderOnly></span>
|
|
7
|
-
|
|
8
|
-
<style>
|
|
9
|
-
.loader {
|
|
10
|
-
width: 16px;
|
|
11
|
-
height: 16px;
|
|
12
|
-
border: 3px solid #FFF;
|
|
13
|
-
border-bottom-color: transparent;
|
|
14
|
-
border-radius: 50%;
|
|
15
|
-
display: inline-block;
|
|
16
|
-
box-sizing: border-box;
|
|
17
|
-
animation: rotation 1s linear infinite;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
@keyframes rotation {
|
|
21
|
-
0% {
|
|
22
|
-
transform: rotate(0deg);
|
|
23
|
-
}
|
|
24
|
-
100% {
|
|
25
|
-
transform: rotate(360deg);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
</style>
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { TagSet } from '@txstate-mws/carbon-svelte'
|
|
3
|
-
import type { TagItem } from '@txstate-mws/carbon-svelte'
|
|
4
|
-
|
|
5
|
-
export let title = ''
|
|
6
|
-
export let subtitle = ''
|
|
7
|
-
export let tags: TagItem[] | undefined = undefined
|
|
8
|
-
</script>
|
|
9
|
-
|
|
10
|
-
<section class="bg-[var(--cds-ui-01)] py-4 px-[16px] text-2xl mb-2">
|
|
11
|
-
<div class="repel">
|
|
12
|
-
<div class="max-w-lg flex flex-col flex-wrap justify-start">
|
|
13
|
-
{#if title}
|
|
14
|
-
<div class="title-block [ flex gap-[12px] ] ">
|
|
15
|
-
<h2 class="text-[1.25rem] text-[var(--cds-text-01,#1A1A1A)] font-normal leading-7">
|
|
16
|
-
{title}
|
|
17
|
-
</h2>
|
|
18
|
-
{#if tags}
|
|
19
|
-
<TagSet tags={tags} />
|
|
20
|
-
{/if}
|
|
21
|
-
</div>
|
|
22
|
-
{#if subtitle}
|
|
23
|
-
<p class="text-sm text-[var(--cds-text-02)] leading-[18px] tracking-[0.16px] pt-2">
|
|
24
|
-
{subtitle}
|
|
25
|
-
</p>
|
|
26
|
-
{/if}
|
|
27
|
-
{/if}
|
|
28
|
-
<!-- Optional content slot below title/subtitle -->
|
|
29
|
-
{#if $$slots.default}
|
|
30
|
-
<div class="mt-2">
|
|
31
|
-
<slot />
|
|
32
|
-
</div>
|
|
33
|
-
{/if}
|
|
34
|
-
</div>
|
|
35
|
-
{#if $$slots['block-end']}
|
|
36
|
-
<div class="block-end-slot">
|
|
37
|
-
<slot name="block-end" />
|
|
38
|
-
</div>
|
|
39
|
-
{/if}
|
|
40
|
-
</div>
|
|
41
|
-
</section>
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { ActionSet, Panel, TagSet } from '@txstate-mws/carbon-svelte'
|
|
3
|
-
import Tab from "carbon-components-svelte/src/Tabs/Tab.svelte";
|
|
4
|
-
import TabContent from "carbon-components-svelte/src/Tabs/TabContent.svelte";
|
|
5
|
-
import Tabs from "carbon-components-svelte/src/Tabs/Tabs.svelte";
|
|
6
|
-
import Tag from "carbon-components-svelte/src/Tag/Tag.svelte";
|
|
7
|
-
import SettingsEdit from "carbon-icons-svelte/lib/SettingsEdit.svelte";
|
|
8
|
-
import View from "carbon-icons-svelte/lib/View.svelte";
|
|
9
|
-
import { invalidate } from '$app/navigation'
|
|
10
|
-
import { api } from '../api'
|
|
11
|
-
import { page } from '$app/stores'
|
|
12
|
-
import type { UIRegistry } from '../registry'
|
|
13
|
-
import { groupby, pluralize } from 'txstate-utils'
|
|
14
|
-
|
|
15
|
-
export let program: any
|
|
16
|
-
export let sharedProgramRequirements: any
|
|
17
|
-
export let openModal: any
|
|
18
|
-
export let onClick: any
|
|
19
|
-
export let uiRegistry: UIRegistry
|
|
20
|
-
|
|
21
|
-
const disablePeriodProgram = (requirementKey: string) => async () => {
|
|
22
|
-
const res = await api.disablePeriodProgramRequirements($page.params.id!, requirementKey, true)
|
|
23
|
-
await invalidate('api:getPeriodConfigurations')
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const enablePeriodProgram = (requirementKey: string) => async () => {
|
|
27
|
-
const res = await api.disablePeriodProgramRequirements($page.params.id!, requirementKey, false)
|
|
28
|
-
await invalidate('api:getPeriodConfigurations')
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
$: enabledRequirements = Object.entries(groupby(program.requirements.filter(r => r.enabled), 'type'))
|
|
32
|
-
$: disabledRequirements = program.requirements.filter(r => !r.enabled)
|
|
33
|
-
|
|
34
|
-
</script>
|
|
35
|
-
<Panel title={program.title} expandable expanded>
|
|
36
|
-
{#each enabledRequirements as requrementEntries}
|
|
37
|
-
{@const type = requrementEntries[0]}
|
|
38
|
-
{@const requirements = requrementEntries[1]}
|
|
39
|
-
<Panel title='' expandable expanded>
|
|
40
|
-
<div style="display: content" slot="headerLeft">
|
|
41
|
-
<TagSet tags={[{ label: `Applicant: ${type}`, type: 'purple' }]} />
|
|
42
|
-
</div>
|
|
43
|
-
<div style="display: content" slot="headerRight">
|
|
44
|
-
<TagSet tags={[{ label: `${requirements.length} ${pluralize('requirement', requirements.length)}`, type: 'yellow' }]} />
|
|
45
|
-
</div>
|
|
46
|
-
<Tabs autoWidth>
|
|
47
|
-
<Tab label={`Enabled Requirements (${enabledRequirements.length})`} />
|
|
48
|
-
<Tab label={`Disabled Requirements (${disabledRequirements.length})`} />
|
|
49
|
-
<svelte:fragment slot='content'>
|
|
50
|
-
<TabContent>
|
|
51
|
-
{#each requirements as requirement (requirement.key)}
|
|
52
|
-
{@const reqDef = uiRegistry.getRequirement(requirement.key)}
|
|
53
|
-
<Panel title={requirement.title} expandable noPrimaryAction actions={[{ label: 'Configure requirement', onClick: onClick('requirement', requirement), disabled: reqDef?.configureComponent == null || !requirement.configuration.actions.update }, { label: 'Disable Requirement', onClick: disablePeriodProgram(requirement.key) }]}>
|
|
54
|
-
<div style="display: content" slot="headerLeft">
|
|
55
|
-
<TagSet tags={[{ label: 'Requirement', type: 'yellow' }]} />
|
|
56
|
-
</div>
|
|
57
|
-
<!-- <Button on:click={onClick('requirement', requirement)} type="primary" size="small" icon={SettingsEdit} iconDescription="Edit Configuration" disabled={reqDef.configureComponent == null || !requirement.configuration.actions.update} /> -->
|
|
58
|
-
<div style="display: content" slot="headerRight">
|
|
59
|
-
{@const tags = sharedProgramRequirements[requirement.key]?.length > 1 ? [{ label: 'Shared', onClick: openModal(requirement.key) }] : []}
|
|
60
|
-
<TagSet tags={tags} />
|
|
61
|
-
</div>
|
|
62
|
-
|
|
63
|
-
<ul class="prompts">
|
|
64
|
-
{#each requirement.prompts as prompt (prompt.key)}
|
|
65
|
-
{@const promptDef = uiRegistry.getPrompt(prompt.key)}
|
|
66
|
-
<li class="prompt justify-between">
|
|
67
|
-
<span>
|
|
68
|
-
<Tag type='green'>Prompt</Tag>{prompt.title}
|
|
69
|
-
</span>
|
|
70
|
-
<ActionSet
|
|
71
|
-
actions={[
|
|
72
|
-
// { label: 'View', icon: View },
|
|
73
|
-
{ label: 'settings', icon: SettingsEdit, disabled: promptDef?.configureComponent == null || !prompt.configuration.actions.update, onClick: onClick('prompt', prompt) }
|
|
74
|
-
]}
|
|
75
|
-
/>
|
|
76
|
-
</li>
|
|
77
|
-
{/each}
|
|
78
|
-
</ul>
|
|
79
|
-
</Panel>
|
|
80
|
-
{/each}
|
|
81
|
-
</TabContent>
|
|
82
|
-
<TabContent>
|
|
83
|
-
{#each disabledRequirements as requirement (requirement.key)}
|
|
84
|
-
<Panel title={requirement.title} actions={[{ label: 'Enable Requirement', onClick: enablePeriodProgram(requirement.key) }]}>
|
|
85
|
-
Requirement: {requirement.title}
|
|
86
|
-
<ul class="prompts">
|
|
87
|
-
{#each requirement.prompts as prompt (prompt.key)}
|
|
88
|
-
<li class="prompt">
|
|
89
|
-
Prompt: {prompt.title}
|
|
90
|
-
</li>
|
|
91
|
-
{/each}
|
|
92
|
-
</ul>
|
|
93
|
-
</Panel>
|
|
94
|
-
{/each}
|
|
95
|
-
</TabContent>
|
|
96
|
-
</svelte:fragment>
|
|
97
|
-
</Tabs>
|
|
98
|
-
</Panel>
|
|
99
|
-
{/each}
|
|
100
|
-
</Panel>
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import InlineNotification from "carbon-components-svelte/src/Notification/InlineNotification.svelte";
|
|
3
|
-
import type { PromptDefinition } from '../registry'
|
|
4
|
-
|
|
5
|
-
export let def: PromptDefinition | undefined
|
|
6
|
-
export let appRequestId: string
|
|
7
|
-
export let appData: Record<string, any>
|
|
8
|
-
export let prompt: { key: string, answered: boolean, moot: boolean | null, invalidated: boolean | null, invalidatedReason: string | null }
|
|
9
|
-
export let configData: Record<string, any>
|
|
10
|
-
export let gatheredConfigData: Record<string, any>
|
|
11
|
-
export let showMoot = false
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<svelte:boundary onerror={e => console.error(e)}>
|
|
15
|
-
{#if showMoot && prompt.moot}
|
|
16
|
-
<em>Already disqualified.</em>
|
|
17
|
-
{:else if !prompt.answered}
|
|
18
|
-
<em>Incomplete</em>
|
|
19
|
-
{:else if !def?.displayComponent}
|
|
20
|
-
<em>No display component registered.</em>
|
|
21
|
-
<pre>{JSON.stringify(appData[prompt.key] ?? {}, null, 2)}</pre>
|
|
22
|
-
{:else}
|
|
23
|
-
<svelte:component this={def.displayComponent} {appRequestId} data={appData[prompt.key]} appRequestData={appData} {configData} {gatheredConfigData} />
|
|
24
|
-
{/if}
|
|
25
|
-
{#if prompt.invalidated && (showMoot || !prompt.moot)}
|
|
26
|
-
<InlineNotification kind="warning" title="Correction Needed" subtitle={prompt.invalidatedReason ?? undefined} class="mt-2" lowContrast hideCloseButton />
|
|
27
|
-
{/if}
|
|
28
|
-
{#snippet failed()}
|
|
29
|
-
<div class="error">
|
|
30
|
-
<div>Error Loading Component</div>
|
|
31
|
-
<p>There was an error loading the display component for this prompt.</p>
|
|
32
|
-
</div>
|
|
33
|
-
{/snippet}
|
|
34
|
-
</svelte:boundary>
|
|
35
|
-
|
|
36
|
-
<style>
|
|
37
|
-
.error div { font-weight: bold; }
|
|
38
|
-
</style>
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { base } from "$app/paths"
|
|
3
|
-
import { ColumnList, FieldDate, FieldMultiselect, Pagination, type ActionItem } from "@txstate-mws/carbon-svelte"
|
|
4
|
-
import { DateTime } from "luxon"
|
|
5
|
-
import View from 'carbon-icons-svelte/lib/View.svelte'
|
|
6
|
-
import DocExport from 'carbon-icons-svelte/lib/DocumentExport.svelte'
|
|
7
|
-
import { downloadCsv } from "../csv"
|
|
8
|
-
import type { AppRequest } from "../typed-client"
|
|
9
|
-
import { pluralize } from "txstate-utils"
|
|
10
|
-
|
|
11
|
-
export let data: AppRequest[]
|
|
12
|
-
export let title: string
|
|
13
|
-
export let subtitle: string
|
|
14
|
-
|
|
15
|
-
const selectedActions = (rows: AppRequest[]): ActionItem[] => [
|
|
16
|
-
{
|
|
17
|
-
label: `Download ${rows.length} ${pluralize('application', rows.length)}`,
|
|
18
|
-
// icon: TrashCan,
|
|
19
|
-
onClick: () => { console.log(rows); downloadCsv(formatCSVData(rows)) }
|
|
20
|
-
}
|
|
21
|
-
]
|
|
22
|
-
|
|
23
|
-
function formatCSVData (d: AppRequest[]) {
|
|
24
|
-
return d.map(d => ({
|
|
25
|
-
Id: d.id,
|
|
26
|
-
Period: d.period.name,
|
|
27
|
-
'TXST ID': d.applicant.otherInfo,
|
|
28
|
-
Name: d.applicant.fullname,
|
|
29
|
-
'Date Submitted': DateTime.fromISO(d.createdAt).toFormat('f').replace(',', ''),
|
|
30
|
-
Benefit: `"${d.applications.map(a => a.title).join(', ')}"`,
|
|
31
|
-
'Last Submitted': DateTime.fromISO(d.updatedAt).toFormat('f').replace(',', '')
|
|
32
|
-
}))
|
|
33
|
-
}
|
|
34
|
-
</script>
|
|
35
|
-
|
|
36
|
-
<div class="flow [ p-4 bg-gray-100 ]">
|
|
37
|
-
<h2 class="[ text-lg ]">{title}</h2>
|
|
38
|
-
<p class="[ text-gray-600 ]">{subtitle}</p>
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<ColumnList
|
|
42
|
-
searchable
|
|
43
|
-
filterTitle='Request Filters'
|
|
44
|
-
{selectedActions}
|
|
45
|
-
listActions={[
|
|
46
|
-
{ label: 'Download', icon: DocExport, onClick: () => { console.log(data); downloadCsv(formatCSVData(data)) } }
|
|
47
|
-
]}
|
|
48
|
-
columns={[
|
|
49
|
-
{ id: 'request', label: 'Request #', tags: (row) => [{ label: String(row.id), }] },
|
|
50
|
-
{ id: 'period', label: 'Period', render: r => r.period.name },
|
|
51
|
-
{ id: 'aNumber', label: 'TXST ID' },
|
|
52
|
-
{ id: 'name', label: 'Name', get: 'applicant.fullname' },
|
|
53
|
-
{ id: 'dateSubmitted', label: 'Date Submitted', render: r => DateTime.fromISO(r.createdAt).toFormat('f') },
|
|
54
|
-
{ id: 'benefit', label: 'Benefit', render: r => r.applications.map(a => a.title).join(', ') },
|
|
55
|
-
{ id: 'lastUpdated', label: 'Last Updated', render: r => DateTime.fromISO(r.updatedAt).toFormat('f') },
|
|
56
|
-
]}
|
|
57
|
-
rows={data}
|
|
58
|
-
title="App Requests"
|
|
59
|
-
|
|
60
|
-
actions={r => [
|
|
61
|
-
{
|
|
62
|
-
label: 'View',
|
|
63
|
-
icon: View,
|
|
64
|
-
// href: `${base}/requests/${r.id}/apply`
|
|
65
|
-
href: `${base}/requests/${r.id}/approve`
|
|
66
|
-
}
|
|
67
|
-
]}
|
|
68
|
-
>
|
|
69
|
-
<svelte:fragment slot="filters">
|
|
70
|
-
<FieldMultiselect
|
|
71
|
-
path="period"
|
|
72
|
-
labelText="Period"
|
|
73
|
-
items={[]}
|
|
74
|
-
placeholder="Choose one or more"
|
|
75
|
-
/>
|
|
76
|
-
<FieldDate
|
|
77
|
-
path='dateSubmitted'
|
|
78
|
-
label='Date Submitted'
|
|
79
|
-
/>
|
|
80
|
-
<FieldMultiselect
|
|
81
|
-
path="test"
|
|
82
|
-
labelText="Period"
|
|
83
|
-
items={[]}
|
|
84
|
-
placeholder="Choose one or more"
|
|
85
|
-
/>
|
|
86
|
-
</svelte:fragment>
|
|
87
|
-
</ColumnList>
|
|
88
|
-
|
|
89
|
-
<Pagination
|
|
90
|
-
totalItems={data.length}
|
|
91
|
-
pageSize={25}
|
|
92
|
-
chooseSize
|
|
93
|
-
/>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { BadgeNumber } from '@txstate-mws/carbon-svelte'
|
|
3
|
-
import Accordion from "carbon-components-svelte/src/Accordion/Accordion.svelte";
|
|
4
|
-
import AccordionItem from "carbon-components-svelte/src/Accordion/AccordionItem.svelte";
|
|
5
|
-
|
|
6
|
-
export let items: { id: string, message: string }[] = []
|
|
7
|
-
export let variant: 'warning' | 'error' = 'error'
|
|
8
|
-
export let accordionTitle = 'Multiple items'
|
|
9
|
-
|
|
10
|
-
$: badgeStyle = variant === 'warning'
|
|
11
|
-
? '--badge-bg: var(--yellow-01, #F3D690); --badge-text: #6F510C'
|
|
12
|
-
: '--badge-bg: #FBE9EA; --badge-text: #a11c25'
|
|
13
|
-
</script>
|
|
14
|
-
|
|
15
|
-
{#if items.length === 1}
|
|
16
|
-
<div class="flex items-center">
|
|
17
|
-
<BadgeNumber value={1} class="mt-2 mr-2" style={badgeStyle} />
|
|
18
|
-
<p class="mt-2 mb-0 text-sm">{items[0].message}</p>
|
|
19
|
-
</div>
|
|
20
|
-
{:else if items.length > 1}
|
|
21
|
-
<div class="flex">
|
|
22
|
-
<BadgeNumber value={items.length} class="mt-5 mr-2" style={badgeStyle} />
|
|
23
|
-
<div class="mt-2 w-full">
|
|
24
|
-
<Accordion align="start">
|
|
25
|
-
<AccordionItem title={accordionTitle}>
|
|
26
|
-
<ol class="list-decimal">
|
|
27
|
-
{#each items as item (item.id)}
|
|
28
|
-
<li>{item.message}</li>
|
|
29
|
-
{/each}
|
|
30
|
-
</ol>
|
|
31
|
-
</AccordionItem>
|
|
32
|
-
</Accordion>
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
{/if}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import WarningAltFilled from "carbon-icons-svelte/lib/WarningAltFilled.svelte";
|
|
3
|
-
import type { ComponentProps } from 'svelte'
|
|
4
|
-
|
|
5
|
-
interface $$Props extends ComponentProps<typeof WarningAltFilled> {}
|
|
6
|
-
</script>
|
|
7
|
-
|
|
8
|
-
<div>
|
|
9
|
-
<WarningAltFilled {...$$restProps} />
|
|
10
|
-
</div>
|
|
11
|
-
|
|
12
|
-
<style>
|
|
13
|
-
div :global(svg) {
|
|
14
|
-
fill: var(--cds-support-03, rgba(239, 200, 108, 1)) !important;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
div :global([data-icon-path="inner-path"]) {
|
|
18
|
-
fill: black;
|
|
19
|
-
}
|
|
20
|
-
</style>
|