@happyvertical/smrt-projects 0.39.4 → 0.39.7

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.
Files changed (83) hide show
  1. package/AGENTS.md +36 -1
  2. package/SERVICE_TIME_MIGRATION.md +23 -0
  3. package/dist/collections/DevelopmentRequestHistories.d.ts +7 -0
  4. package/dist/collections/DevelopmentRequestHistories.d.ts.map +1 -0
  5. package/dist/collections/DevelopmentRequests.d.ts +20 -0
  6. package/dist/collections/DevelopmentRequests.d.ts.map +1 -0
  7. package/dist/collections/ProjectIntegrationAudits.d.ts +7 -0
  8. package/dist/collections/ProjectIntegrationAudits.d.ts.map +1 -0
  9. package/dist/collections/ProjectIntegrations.d.ts +28 -0
  10. package/dist/collections/ProjectIntegrations.d.ts.map +1 -0
  11. package/dist/index.d.ts +13 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1673 -33
  14. package/dist/index.js.map +1 -1
  15. package/dist/managed-client.d.ts +13 -0
  16. package/dist/managed-client.d.ts.map +1 -0
  17. package/dist/manifest.json +4790 -1109
  18. package/dist/models/DevelopmentRequest.d.ts +35 -0
  19. package/dist/models/DevelopmentRequest.d.ts.map +1 -0
  20. package/dist/models/DevelopmentRequestHistory.d.ts +22 -0
  21. package/dist/models/DevelopmentRequestHistory.d.ts.map +1 -0
  22. package/dist/models/ProjectIntegration.d.ts +24 -0
  23. package/dist/models/ProjectIntegration.d.ts.map +1 -0
  24. package/dist/models/ProjectIntegrationAudit.d.ts +16 -0
  25. package/dist/models/ProjectIntegrationAudit.d.ts.map +1 -0
  26. package/dist/models/delivery-control-plane.d.ts +83 -0
  27. package/dist/models/delivery-control-plane.d.ts.map +1 -0
  28. package/dist/models/service-evidence.d.ts +79 -0
  29. package/dist/models/service-evidence.d.ts.map +1 -0
  30. package/dist/services/assistance-request-service.d.ts +45 -0
  31. package/dist/services/assistance-request-service.d.ts.map +1 -0
  32. package/dist/services/delivery-service.d.ts +55 -0
  33. package/dist/services/delivery-service.d.ts.map +1 -0
  34. package/dist/services/development-request-service.d.ts +61 -0
  35. package/dist/services/development-request-service.d.ts.map +1 -0
  36. package/dist/services/index.d.ts +6 -0
  37. package/dist/services/index.d.ts.map +1 -0
  38. package/dist/services/service-evidence-service.d.ts +48 -0
  39. package/dist/services/service-evidence-service.d.ts.map +1 -0
  40. package/dist/services/subscription-commercial-resolver.d.ts +17 -0
  41. package/dist/services/subscription-commercial-resolver.d.ts.map +1 -0
  42. package/dist/smrt-knowledge.json +1823 -148
  43. package/dist/svelte/AssistanceLauncher.svelte +96 -0
  44. package/dist/svelte/AssistanceLauncher.svelte.d.ts +12 -0
  45. package/dist/svelte/AssistanceLauncher.svelte.d.ts.map +1 -0
  46. package/dist/svelte/DeliveryStatus.svelte +71 -0
  47. package/dist/svelte/DeliveryStatus.svelte.d.ts +8 -0
  48. package/dist/svelte/DeliveryStatus.svelte.d.ts.map +1 -0
  49. package/dist/svelte/DevelopmentBoard.svelte +103 -0
  50. package/dist/svelte/DevelopmentBoard.svelte.d.ts +10 -0
  51. package/dist/svelte/DevelopmentBoard.svelte.d.ts.map +1 -0
  52. package/dist/svelte/DevelopmentRequestDetail.svelte +92 -0
  53. package/dist/svelte/DevelopmentRequestDetail.svelte.d.ts +9 -0
  54. package/dist/svelte/DevelopmentRequestDetail.svelte.d.ts.map +1 -0
  55. package/dist/svelte/PreviewApprovalPanel.svelte +63 -0
  56. package/dist/svelte/PreviewApprovalPanel.svelte.d.ts +10 -0
  57. package/dist/svelte/PreviewApprovalPanel.svelte.d.ts.map +1 -0
  58. package/dist/svelte/ServiceEvidenceList.svelte +103 -0
  59. package/dist/svelte/ServiceEvidenceList.svelte.d.ts +8 -0
  60. package/dist/svelte/ServiceEvidenceList.svelte.d.ts.map +1 -0
  61. package/dist/svelte/components/DevelopmentRequestForm.svelte +70 -0
  62. package/dist/svelte/components/DevelopmentRequestForm.svelte.d.ts +19 -0
  63. package/dist/svelte/components/DevelopmentRequestForm.svelte.d.ts.map +1 -0
  64. package/dist/svelte/components/DevelopmentRequestList.svelte +218 -0
  65. package/dist/svelte/components/DevelopmentRequestList.svelte.d.ts +22 -0
  66. package/dist/svelte/components/DevelopmentRequestList.svelte.d.ts.map +1 -0
  67. package/dist/svelte/components/__tests__/DeliverySurfaces.test.js +98 -0
  68. package/dist/svelte/components/__tests__/DevelopmentRequest.test.js +52 -0
  69. package/dist/svelte/delivery-types.d.ts +36 -0
  70. package/dist/svelte/delivery-types.d.ts.map +1 -0
  71. package/dist/svelte/delivery-types.js +1 -0
  72. package/dist/svelte/i18n.d.ts +30 -0
  73. package/dist/svelte/i18n.d.ts.map +1 -1
  74. package/dist/svelte/i18n.js +30 -0
  75. package/dist/svelte/index.d.ts +18 -1
  76. package/dist/svelte/index.d.ts.map +1 -1
  77. package/dist/svelte/index.js +18 -1
  78. package/dist/types.d.ts +79 -0
  79. package/dist/types.d.ts.map +1 -1
  80. package/dist/ui.d.ts.map +1 -1
  81. package/dist/ui.js +106 -10
  82. package/dist/ui.js.map +1 -1
  83. package/package.json +11 -9
@@ -0,0 +1,96 @@
1
+ <script lang="ts">
2
+ import { Form, Input, Textarea } from '@happyvertical/smrt-ui/forms';
3
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
4
+ import { Button } from '@happyvertical/smrt-ui/ui';
5
+ import type {
6
+ DevelopmentRequestEvidence,
7
+ ManagedAssistanceRequestInput,
8
+ } from '../types.js';
9
+ import { M } from './i18n.js';
10
+
11
+ export interface Props {
12
+ requesterId: string;
13
+ applicationContext?: Record<string, unknown>;
14
+ evidence?: DevelopmentRequestEvidence[];
15
+ disabled?: boolean;
16
+ onsubmit?: (value: ManagedAssistanceRequestInput) => void | Promise<void>;
17
+ }
18
+
19
+ let {
20
+ requesterId,
21
+ applicationContext = {},
22
+ evidence = [],
23
+ disabled = false,
24
+ onsubmit,
25
+ }: Props = $props();
26
+ const { t } = useI18n();
27
+ let subject = $state('');
28
+ let message = $state('');
29
+
30
+ async function submit(event: SubmitEvent) {
31
+ event.preventDefault();
32
+ if (disabled || !onsubmit || !subject.trim() || !message.trim()) return;
33
+ await onsubmit({
34
+ requesterId,
35
+ subject: subject.trim(),
36
+ applicationContext,
37
+ conversation: [{ body: message.trim() }],
38
+ evidence,
39
+ });
40
+ subject = '';
41
+ message = '';
42
+ }
43
+ </script>
44
+
45
+ <section class="assistance">
46
+ <Form onsubmit={submit}>
47
+ <header>
48
+ <h2>{t(M['projects.assistance.title'])}</h2>
49
+ <p>{t(M['projects.assistance.description'])}</p>
50
+ </header>
51
+ <label>
52
+ {t(M['projects.assistance.subject'])}
53
+ <Input bind:value={subject} required {disabled} />
54
+ </label>
55
+ <label>
56
+ {t(M['projects.assistance.need'])}
57
+ <Textarea bind:value={message} rows={4} required {disabled}></Textarea>
58
+ </label>
59
+ <footer>
60
+ <Button type="submit" {disabled}>
61
+ {t(M['projects.assistance.submit'])}
62
+ </Button>
63
+ </footer>
64
+ </Form>
65
+ </section>
66
+
67
+ <style>
68
+ .assistance {
69
+ max-width: 42rem;
70
+ }
71
+ .assistance :global(form) {
72
+ display: grid;
73
+ gap: var(--smrt-spacing-4);
74
+ }
75
+ .assistance header {
76
+ border-bottom: 1px solid var(--smrt-color-outline-variant);
77
+ padding-bottom: var(--smrt-spacing-3);
78
+ }
79
+ .assistance h2,
80
+ .assistance p {
81
+ margin: 0;
82
+ }
83
+ .assistance p {
84
+ color: var(--smrt-color-on-surface-variant);
85
+ margin-top: var(--smrt-spacing-1);
86
+ }
87
+ .assistance label {
88
+ display: grid;
89
+ font-weight: 600;
90
+ gap: var(--smrt-spacing-1);
91
+ }
92
+ .assistance footer {
93
+ display: flex;
94
+ justify-content: flex-end;
95
+ }
96
+ </style>
@@ -0,0 +1,12 @@
1
+ import type { DevelopmentRequestEvidence, ManagedAssistanceRequestInput } from '../types.js';
2
+ export interface Props {
3
+ requesterId: string;
4
+ applicationContext?: Record<string, unknown>;
5
+ evidence?: DevelopmentRequestEvidence[];
6
+ disabled?: boolean;
7
+ onsubmit?: (value: ManagedAssistanceRequestInput) => void | Promise<void>;
8
+ }
9
+ declare const AssistanceLauncher: import("svelte").Component<Props, {}, "">;
10
+ type AssistanceLauncher = ReturnType<typeof AssistanceLauncher>;
11
+ export default AssistanceLauncher;
12
+ //# sourceMappingURL=AssistanceLauncher.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssistanceLauncher.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/AssistanceLauncher.svelte.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,0BAA0B,EAC1B,6BAA6B,EAC9B,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,KAAK;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,0BAA0B,EAAE,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E;AA6DD,QAAA,MAAM,kBAAkB,2CAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,71 @@
1
+ <script lang="ts">
2
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
+ import type { DeliveryEventView } from './delivery-types.js';
4
+ import { M } from './i18n.js';
5
+
6
+ export interface Props {
7
+ events?: DeliveryEventView[];
8
+ }
9
+
10
+ let { events = [] }: Props = $props();
11
+ const { t } = useI18n();
12
+ const format = (value: Date | string) =>
13
+ new Intl.DateTimeFormat(undefined, {
14
+ dateStyle: 'medium',
15
+ timeStyle: 'short',
16
+ }).format(new Date(value));
17
+ </script>
18
+
19
+ <ol class="delivery" aria-label={t(M['projects.delivery_status.aria'])}>
20
+ {#each [...events].sort((a, b) => a.sequence - b.sequence) as event (event.id)}
21
+ <li>
22
+ <span class="marker" aria-hidden="true"></span>
23
+ <div>
24
+ <strong>{event.label ?? event.type.replaceAll('_', ' ')}</strong>
25
+ {#if event.detail}<p>{event.detail}</p>{/if}
26
+ <time datetime={new Date(event.occurredAt).toISOString()}>
27
+ {format(event.occurredAt)}
28
+ </time>
29
+ </div>
30
+ </li>
31
+ {/each}
32
+ </ol>
33
+
34
+ <style>
35
+ .delivery {
36
+ list-style: none;
37
+ margin: 0;
38
+ padding: 0;
39
+ }
40
+ .delivery li {
41
+ display: grid;
42
+ gap: var(--smrt-spacing-3);
43
+ grid-template-columns: 1rem 1fr;
44
+ padding-bottom: var(--smrt-spacing-5);
45
+ position: relative;
46
+ }
47
+ .delivery li:not(:last-child)::before {
48
+ background: var(--smrt-color-outline-variant);
49
+ content: '';
50
+ height: 100%;
51
+ left: 0.35rem;
52
+ position: absolute;
53
+ top: 0.65rem;
54
+ width: 1px;
55
+ }
56
+ .marker {
57
+ background: var(--smrt-color-primary);
58
+ border-radius: var(--smrt-radius-full);
59
+ height: 0.7rem;
60
+ margin-top: var(--smrt-spacing-1);
61
+ width: 0.7rem;
62
+ z-index: 1;
63
+ }
64
+ .delivery p {
65
+ margin: var(--smrt-spacing-1) 0;
66
+ }
67
+ .delivery time {
68
+ color: var(--smrt-color-on-surface-variant);
69
+ font-size: var(--smrt-typography-label-small-size);
70
+ }
71
+ </style>
@@ -0,0 +1,8 @@
1
+ import type { DeliveryEventView } from './delivery-types.js';
2
+ export interface Props {
3
+ events?: DeliveryEventView[];
4
+ }
5
+ declare const DeliveryStatus: import("svelte").Component<Props, {}, "">;
6
+ type DeliveryStatus = ReturnType<typeof DeliveryStatus>;
7
+ export default DeliveryStatus;
8
+ //# sourceMappingURL=DeliveryStatus.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeliveryStatus.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/DeliveryStatus.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAI7D,MAAM,WAAW,KAAK;IACpB,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAmCD,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -0,0 +1,103 @@
1
+ <script lang="ts">
2
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
+ import type { DevelopmentRequestView } from './delivery-types.js';
4
+ import { M } from './i18n.js';
5
+
6
+ export interface Props {
7
+ requests?: DevelopmentRequestView[];
8
+ columns?: string[];
9
+ onselect?: (request: DevelopmentRequestView) => void;
10
+ }
11
+
12
+ let {
13
+ requests = [],
14
+ columns = ['submitted', 'triaged', 'planned', 'in_progress', 'completed'],
15
+ onselect,
16
+ }: Props = $props();
17
+ const { t } = useI18n();
18
+ const inColumn = (column: string) =>
19
+ requests.filter(
20
+ (request) =>
21
+ (request.deliveryStatus || request.status).toLowerCase() ===
22
+ column.toLowerCase(),
23
+ );
24
+ </script>
25
+
26
+ <section class="board" aria-label={t(M['projects.development_board.aria'])}>
27
+ {#if requests.length === 0}
28
+ <p class="empty">{t(M['projects.development_board.empty'])}</p>
29
+ {:else}
30
+ {#each columns as column (column)}
31
+ <div class="lane">
32
+ <header>
33
+ <h3>{column.replaceAll('_', ' ')}</h3>
34
+ <span>{inColumn(column).length}</span>
35
+ </header>
36
+ <div class="lane__items">
37
+ {#each inColumn(column) as request (request.id)}
38
+ <!-- raw-primitive-allow: each board row is a semantic selection control -->
39
+ <button type="button" onclick={() => onselect?.(request)}>
40
+ <strong>{request.title ?? request.description}</strong>
41
+ <small>
42
+ {request.type}
43
+ {request.requesterLabel ? ` · ${request.requesterLabel}` : ''}
44
+ </small>
45
+ </button>
46
+ {/each}
47
+ </div>
48
+ </div>
49
+ {/each}
50
+ {/if}
51
+ </section>
52
+
53
+ <style>
54
+ .board {
55
+ display: grid;
56
+ gap: var(--smrt-spacing-5);
57
+ grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
58
+ overflow-x: auto;
59
+ }
60
+ .lane {
61
+ min-width: 0;
62
+ }
63
+ .empty {
64
+ color: var(--smrt-color-on-surface-variant);
65
+ grid-column: 1 / -1;
66
+ margin: 0;
67
+ padding: var(--smrt-spacing-5) var(--smrt-spacing-1);
68
+ }
69
+ .lane header {
70
+ align-items: center;
71
+ border-bottom: 2px solid var(--smrt-color-primary);
72
+ display: flex;
73
+ justify-content: space-between;
74
+ padding: var(--smrt-spacing-2) var(--smrt-spacing-1);
75
+ }
76
+ .lane h3 {
77
+ font-size: var(--smrt-typography-label-medium-size);
78
+ margin: 0;
79
+ text-transform: uppercase;
80
+ }
81
+ .lane__items {
82
+ display: grid;
83
+ }
84
+ .lane__items button {
85
+ background: transparent;
86
+ border: 0;
87
+ border-bottom: 1px solid var(--smrt-color-outline-variant);
88
+ color: inherit;
89
+ cursor: pointer;
90
+ display: grid;
91
+ gap: var(--smrt-spacing-1);
92
+ padding: var(--smrt-spacing-4) var(--smrt-spacing-1);
93
+ text-align: left;
94
+ transition: transform 120ms ease;
95
+ }
96
+ .lane__items button:hover,
97
+ .lane__items button:focus-visible {
98
+ transform: translateX(var(--smrt-spacing-1));
99
+ }
100
+ .lane small {
101
+ color: var(--smrt-color-on-surface-variant);
102
+ }
103
+ </style>
@@ -0,0 +1,10 @@
1
+ import type { DevelopmentRequestView } from './delivery-types.js';
2
+ export interface Props {
3
+ requests?: DevelopmentRequestView[];
4
+ columns?: string[];
5
+ onselect?: (request: DevelopmentRequestView) => void;
6
+ }
7
+ declare const DevelopmentBoard: import("svelte").Component<Props, {}, "">;
8
+ type DevelopmentBoard = ReturnType<typeof DevelopmentBoard>;
9
+ export default DevelopmentBoard;
10
+ //# sourceMappingURL=DevelopmentBoard.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevelopmentBoard.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/DevelopmentBoard.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAIlE,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACtD;AAoDD,QAAA,MAAM,gBAAgB,2CAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,92 @@
1
+ <script lang="ts">
2
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
+ import DeliveryStatus from './DeliveryStatus.svelte';
4
+ import type {
5
+ DeliveryEventView,
6
+ DevelopmentRequestView,
7
+ } from './delivery-types.js';
8
+ import { M } from './i18n.js';
9
+
10
+ export interface Props {
11
+ request: DevelopmentRequestView;
12
+ events?: DeliveryEventView[];
13
+ }
14
+
15
+ let { request, events = [] }: Props = $props();
16
+ const { t } = useI18n();
17
+ </script>
18
+
19
+ <article
20
+ class="detail"
21
+ aria-label={t(M['projects.development_request.detail_aria'])}
22
+ >
23
+ <header>
24
+ <div>
25
+ <span>{request.type}</span>
26
+ <h2>{request.title ?? request.description}</h2>
27
+ </div>
28
+ <strong>{request.deliveryStatus ?? request.status}</strong>
29
+ </header>
30
+
31
+ {#if request.title}<p>{request.description}</p>{/if}
32
+
33
+ <dl>
34
+ <div>
35
+ <dt>{t(M['projects.development_request.status'])}</dt>
36
+ <dd>{request.deliveryStatus ?? request.status}</dd>
37
+ </div>
38
+ {#if request.visibility}
39
+ <div>
40
+ <dt>{t(M['projects.development_request.visibility'])}</dt>
41
+ <dd>{request.visibility}</dd>
42
+ </div>
43
+ {/if}
44
+ {#if request.requesterLabel}
45
+ <div>
46
+ <dt>{t(M['projects.development_request.requester'])}</dt>
47
+ <dd>{request.requesterLabel}</dd>
48
+ </div>
49
+ {/if}
50
+ </dl>
51
+
52
+ {#if events.length > 0}<DeliveryStatus {events} />{/if}
53
+ </article>
54
+
55
+ <style>
56
+ .detail {
57
+ display: grid;
58
+ gap: var(--smrt-spacing-5);
59
+ }
60
+ header {
61
+ align-items: start;
62
+ border-bottom: 1px solid var(--smrt-color-outline-variant);
63
+ display: flex;
64
+ gap: var(--smrt-spacing-5);
65
+ justify-content: space-between;
66
+ padding-bottom: var(--smrt-spacing-4);
67
+ }
68
+ header div {
69
+ display: grid;
70
+ gap: var(--smrt-spacing-1);
71
+ }
72
+ header span,
73
+ dt {
74
+ color: var(--smrt-color-on-surface-variant);
75
+ font-size: var(--smrt-typography-label-medium-size);
76
+ }
77
+ h2,
78
+ p,
79
+ dl,
80
+ dd {
81
+ margin: 0;
82
+ }
83
+ dl {
84
+ display: flex;
85
+ flex-wrap: wrap;
86
+ gap: var(--smrt-spacing-5);
87
+ }
88
+ dl div {
89
+ display: grid;
90
+ gap: var(--smrt-spacing-1);
91
+ }
92
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { DeliveryEventView, DevelopmentRequestView } from './delivery-types.js';
2
+ export interface Props {
3
+ request: DevelopmentRequestView;
4
+ events?: DeliveryEventView[];
5
+ }
6
+ declare const DevelopmentRequestDetail: import("svelte").Component<Props, {}, "">;
7
+ type DevelopmentRequestDetail = ReturnType<typeof DevelopmentRequestDetail>;
8
+ export default DevelopmentRequestDetail;
9
+ //# sourceMappingURL=DevelopmentRequestDetail.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevelopmentRequestDetail.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/DevelopmentRequestDetail.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,iBAAiB,EACjB,sBAAsB,EACvB,MAAM,qBAAqB,CAAC;AAI7B,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,sBAAsB,CAAC;IAChC,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAiDD,QAAA,MAAM,wBAAwB,2CAAwC,CAAC;AACvE,KAAK,wBAAwB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC5E,eAAe,wBAAwB,CAAC"}
@@ -0,0 +1,63 @@
1
+ <script lang="ts">
2
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
+ import { Button } from '@happyvertical/smrt-ui/ui';
4
+ import type { PreviewApprovalView } from './delivery-types.js';
5
+ import { M } from './i18n.js';
6
+
7
+ export interface Props {
8
+ preview: PreviewApprovalView;
9
+ busy?: boolean;
10
+ ondecide?: (approved: boolean) => void | Promise<void>;
11
+ }
12
+
13
+ let { preview, busy = false, ondecide }: Props = $props();
14
+ const { t } = useI18n();
15
+ </script>
16
+
17
+ <section class="preview">
18
+ <div>
19
+ <span>{t(M['projects.preview.label'], { id: preview.previewId })}</span>
20
+ <strong>{preview.status}</strong>
21
+ </div>
22
+ {#if preview.previewUrl}
23
+ <a href={preview.previewUrl} target="_blank" rel="noopener noreferrer">
24
+ {t(M['projects.preview.open'])}
25
+ </a>
26
+ {/if}
27
+ {#if preview.status === 'pending'}
28
+ <footer>
29
+ <Button
30
+ variant="secondary"
31
+ disabled={busy}
32
+ onclick={() => ondecide?.(false)}
33
+ >
34
+ {t(M['projects.preview.reject'])}
35
+ </Button>
36
+ <Button disabled={busy} onclick={() => ondecide?.(true)}>
37
+ {t(M['projects.preview.approve'])}
38
+ </Button>
39
+ </footer>
40
+ {/if}
41
+ </section>
42
+
43
+ <style>
44
+ .preview {
45
+ border-block: 1px solid var(--smrt-color-outline-variant);
46
+ display: grid;
47
+ gap: var(--smrt-spacing-4);
48
+ padding: var(--smrt-spacing-4) 0;
49
+ }
50
+ .preview > div {
51
+ display: flex;
52
+ justify-content: space-between;
53
+ }
54
+ .preview a {
55
+ color: var(--smrt-color-primary);
56
+ font-weight: 600;
57
+ }
58
+ .preview footer {
59
+ display: flex;
60
+ gap: var(--smrt-spacing-3);
61
+ justify-content: flex-end;
62
+ }
63
+ </style>
@@ -0,0 +1,10 @@
1
+ import type { PreviewApprovalView } from './delivery-types.js';
2
+ export interface Props {
3
+ preview: PreviewApprovalView;
4
+ busy?: boolean;
5
+ ondecide?: (approved: boolean) => void | Promise<void>;
6
+ }
7
+ declare const PreviewApprovalPanel: import("svelte").Component<Props, {}, "">;
8
+ type PreviewApprovalPanel = ReturnType<typeof PreviewApprovalPanel>;
9
+ export default PreviewApprovalPanel;
10
+ //# sourceMappingURL=PreviewApprovalPanel.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PreviewApprovalPanel.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/PreviewApprovalPanel.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAI/D,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAsCD,QAAA,MAAM,oBAAoB,2CAAwC,CAAC;AACnE,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACpE,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,103 @@
1
+ <script lang="ts">
2
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
+ import type { ServiceEvidenceView } from './delivery-types.js';
4
+ import { M } from './i18n.js';
5
+
6
+ export interface Props {
7
+ entries?: ServiceEvidenceView[];
8
+ }
9
+
10
+ let { entries = [] }: Props = $props();
11
+ const { t } = useI18n();
12
+
13
+ const money = (amount = 0, currency = 'USD') =>
14
+ new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(
15
+ amount,
16
+ );
17
+ </script>
18
+
19
+ <section
20
+ class="evidence"
21
+ aria-label={t(M['projects.service_evidence.aria'])}
22
+ >
23
+ {#each entries as entry (entry.id)}
24
+ <article>
25
+ <div>
26
+ <strong>{entry.context}</strong>
27
+ <small>
28
+ {entry.participant} · {(entry.durationSeconds / 3600).toFixed(2)} h ·
29
+ {entry.status}
30
+ </small>
31
+ </div>
32
+ <dl>
33
+ <div>
34
+ <dt>{t(M['projects.service_evidence.client'])}</dt>
35
+ <dd>{money(entry.chargeAmount, entry.currency)}</dd>
36
+ </div>
37
+ <div>
38
+ <dt>{t(M['projects.service_evidence.provider'])}</dt>
39
+ <dd>{money(entry.compensationAmount, entry.currency)}</dd>
40
+ </div>
41
+ <div>
42
+ <dt>{t(M['projects.service_evidence.margin'])}</dt>
43
+ <dd>
44
+ {money(
45
+ (entry.chargeAmount ?? 0) - (entry.compensationAmount ?? 0),
46
+ entry.currency,
47
+ )}
48
+ </dd>
49
+ </div>
50
+ </dl>
51
+ </article>
52
+ {/each}
53
+ </section>
54
+
55
+ <style>
56
+ .evidence {
57
+ border-top: 1px solid var(--smrt-color-outline-variant);
58
+ }
59
+ .evidence article {
60
+ align-items: center;
61
+ border-bottom: 1px solid var(--smrt-color-outline-variant);
62
+ display: grid;
63
+ gap: var(--smrt-spacing-4);
64
+ grid-template-columns: 1fr auto;
65
+ padding: var(--smrt-spacing-4) var(--smrt-spacing-1);
66
+ }
67
+ .evidence article > div {
68
+ display: grid;
69
+ gap: var(--smrt-spacing-1);
70
+ }
71
+ .evidence small,
72
+ .evidence dt {
73
+ color: var(--smrt-color-on-surface-variant);
74
+ }
75
+ .evidence dl {
76
+ display: flex;
77
+ gap: var(--smrt-spacing-5);
78
+ margin: 0;
79
+ }
80
+ .evidence dl div {
81
+ display: grid;
82
+ gap: var(--smrt-spacing-1);
83
+ text-align: right;
84
+ }
85
+ .evidence dt {
86
+ font-size: var(--smrt-typography-label-medium-size);
87
+ }
88
+ .evidence dd {
89
+ font-variant-numeric: tabular-nums;
90
+ margin: 0;
91
+ }
92
+ @media (max-width: 40rem) {
93
+ .evidence article {
94
+ grid-template-columns: 1fr;
95
+ }
96
+ .evidence dl {
97
+ justify-content: space-between;
98
+ }
99
+ .evidence dl div {
100
+ text-align: left;
101
+ }
102
+ }
103
+ </style>
@@ -0,0 +1,8 @@
1
+ import type { ServiceEvidenceView } from './delivery-types.js';
2
+ export interface Props {
3
+ entries?: ServiceEvidenceView[];
4
+ }
5
+ declare const ServiceEvidenceList: import("svelte").Component<Props, {}, "">;
6
+ type ServiceEvidenceList = ReturnType<typeof ServiceEvidenceList>;
7
+ export default ServiceEvidenceList;
8
+ //# sourceMappingURL=ServiceEvidenceList.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceEvidenceList.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/ServiceEvidenceList.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAI/D,MAAM,WAAW,KAAK;IACpB,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAqDD,QAAA,MAAM,mBAAmB,2CAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}