|
1 | 1 | <script lang="ts"> |
2 | 2 | import { currentBank } from "$lib/stores/currentBank.svelte"; |
| 3 | + import { Building2, Globe, KeyRound } from "@lucide/svelte"; |
| 4 | + import RoleSearchWidget from "$lib/components/RoleSearchWidget.svelte"; |
3 | 5 |
|
4 | 6 | const { data, form } = $props(); |
5 | 7 | const userEntitlements = data.userEntitlements; |
|
33 | 35 | ); |
34 | 36 |
|
35 | 37 | let selectedEntitlementRole = $state(""); |
| 38 | + let roleScope = $state<"all" | "system" | "bank">("all"); |
36 | 39 | let selectedBankId = $state(currentBank.bankId); |
37 | 40 |
|
38 | | - $effect(() => { |
39 | | - selectedBankId = currentBank.bankId; |
| 41 | + // Determine if selected role requires bank_id |
| 42 | + let selectedRoleRequiresBank = $derived.by(() => { |
| 43 | + if (selectedEntitlementRole) { |
| 44 | + const role = allEntitlements.find((r: any) => r.role === selectedEntitlementRole); |
| 45 | + if (role) return role.requires_bank_id; |
| 46 | + } |
| 47 | + // When no role selected yet, use scope as hint |
| 48 | + return roleScope === "bank"; |
40 | 49 | }); |
41 | 50 |
|
42 | | - // Derived state to get the full entitlement object |
43 | | - let selectedEntitlement = $derived( |
44 | | - allEntitlements.find((ent) => ent.role === selectedEntitlementRole) || { |
45 | | - role: "", |
46 | | - requires_bank_id: false, |
47 | | - }, |
48 | | - ); |
| 51 | + // Sync bankId based on whether the role needs a bank |
| 52 | + $effect(() => { |
| 53 | + if (selectedRoleRequiresBank) { |
| 54 | + selectedBankId = currentBank.bankId; |
| 55 | + } else { |
| 56 | + selectedBankId = ""; |
| 57 | + } |
| 58 | + }); |
49 | 59 |
|
50 | 60 | // Pre-select entitlement if form data exists (on validation errors) |
51 | 61 | if (form?.entitlement && !form?.success) { |
|
60 | 70 | if (form?.success) { |
61 | 71 | selectedEntitlementRole = ""; |
62 | 72 | } |
63 | | -
|
64 | | - // console.debug('User Entitlements:', userEntitlements); |
65 | | - // console.debug('All Entitlements:', allEntitlements); |
66 | | - console.log("Can Create Entitlements:", canCreateEntitlements); |
67 | 73 | </script> |
68 | 74 |
|
69 | 75 | <h2 class="mb-4 text-xl font-semibold">Your Entitlements</h2> |
|
148 | 154 | <form |
149 | 155 | method="POST" |
150 | 156 | action="?/create" |
151 | | - class="mx-auto w-full max-w-md space-y-4" |
| 157 | + class="w-full max-w-2xl space-y-4" |
152 | 158 | > |
153 | | - <label class="label"> |
154 | | - <span class="label-text">Select Entitlement</span> |
155 | | - <select |
156 | | - class="select" |
157 | | - name="entitlement" |
158 | | - bind:value={selectedEntitlementRole} |
159 | | - > |
160 | | - <option value="" disabled>Select an entitlement</option> |
161 | | - {#each allEntitlements as ent} |
162 | | - <option value={ent.role}>{ent.role}</option> |
163 | | - {/each} |
164 | | - </select> |
165 | | - </label> |
| 159 | + <!-- Hidden inputs for form submission --> |
| 160 | + <input type="hidden" name="entitlement" value={selectedEntitlementRole} /> |
| 161 | + {#if selectedRoleRequiresBank} |
| 162 | + <input type="hidden" name="bank_id" value={selectedBankId} /> |
| 163 | + {/if} |
| 164 | + |
| 165 | + <div class="form-group"> |
| 166 | + <label class="form-label"> |
| 167 | + <KeyRound size={18} /> |
| 168 | + <span>Select Role</span> |
| 169 | + </label> |
| 170 | + <RoleSearchWidget |
| 171 | + roles={allEntitlements} |
| 172 | + bind:selectedRole={selectedEntitlementRole} |
| 173 | + bind:roleScope |
| 174 | + /> |
| 175 | + </div> |
166 | 176 |
|
167 | 177 | {#if form?.missing}<p class="text-error-500 text-xs"> |
168 | 178 | Please select an entitlement to add. |
169 | 179 | </p>{/if} |
170 | 180 | {#if form?.error}<p class="text-error-500 text-xs">{form.error}</p>{/if} |
171 | 181 |
|
172 | | - {#if selectedEntitlement.requires_bank_id} |
173 | | - <input type="hidden" name="bank_id" value={selectedBankId} /> |
174 | | - <div class="label"> |
175 | | - <span class="label-text">Bank</span> |
176 | | - {#if selectedBankId} |
177 | | - <div class="rounded border border-gray-300 bg-gray-50 px-3 py-2 text-sm text-gray-700 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300"> |
178 | | - {selectedBankId} |
179 | | - </div> |
180 | | - {:else} |
181 | | - <p class="text-sm text-amber-600 dark:text-amber-400"> |
182 | | - Please select a bank in <a href="/user" class="underline">My Account</a> first. |
183 | | - </p> |
184 | | - {/if} |
| 182 | + <!-- Bank ID Field (shown for bank-level roles) --> |
| 183 | + {#if selectedRoleRequiresBank} |
| 184 | + <div class="form-group"> |
| 185 | + <label for="bank-id-input" class="form-label"> |
| 186 | + <Building2 size={18} /> |
| 187 | + <span>Bank ID</span> |
| 188 | + </label> |
| 189 | + <input |
| 190 | + type="text" |
| 191 | + id="bank-id-input" |
| 192 | + class="form-input" |
| 193 | + bind:value={selectedBankId} |
| 194 | + placeholder="Enter bank ID" |
| 195 | + /> |
| 196 | + <div class="form-hint"> |
| 197 | + The bank to scope this entitlement to |
| 198 | + </div> |
| 199 | + </div> |
| 200 | + {:else if selectedEntitlementRole} |
| 201 | + <div class="scope-info"> |
| 202 | + <Globe size={16} /> |
| 203 | + <span>This is a system-wide role — no bank ID required</span> |
185 | 204 | </div> |
186 | 205 | {/if} |
| 206 | + |
187 | 207 | <button class="btn preset-outlined-tertiary-500" type="submit" |
188 | 208 | >Add Entitlement</button |
189 | 209 | > |
190 | 210 | </form> |
191 | 211 | {:else if !canCreateEntitlements} |
192 | 212 | <h2 class="mt-8 mb-4 text-xl font-semibold">Request Entitlement</h2> |
193 | 213 | {/if} |
| 214 | + |
| 215 | +<style> |
| 216 | + .form-group { |
| 217 | + display: flex; |
| 218 | + flex-direction: column; |
| 219 | + gap: 0.5rem; |
| 220 | + } |
| 221 | +
|
| 222 | + .form-label { |
| 223 | + display: flex; |
| 224 | + align-items: center; |
| 225 | + gap: 0.5rem; |
| 226 | + font-size: 0.875rem; |
| 227 | + font-weight: 600; |
| 228 | + color: #374151; |
| 229 | + } |
| 230 | +
|
| 231 | + :global([data-mode="dark"]) .form-label { |
| 232 | + color: var(--color-surface-200); |
| 233 | + } |
| 234 | +
|
| 235 | + .form-input { |
| 236 | + width: 100%; |
| 237 | + padding: 0.625rem 0.75rem; |
| 238 | + border: 1px solid #d1d5db; |
| 239 | + border-radius: 6px; |
| 240 | + font-size: 0.875rem; |
| 241 | + transition: all 0.2s; |
| 242 | + } |
| 243 | +
|
| 244 | + .form-input:focus { |
| 245 | + outline: none; |
| 246 | + border-color: #667eea; |
| 247 | + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); |
| 248 | + } |
| 249 | +
|
| 250 | + :global([data-mode="dark"]) .form-input { |
| 251 | + background: rgb(var(--color-surface-700)); |
| 252 | + border-color: rgb(var(--color-surface-600)); |
| 253 | + color: var(--color-surface-100); |
| 254 | + } |
| 255 | +
|
| 256 | + :global([data-mode="dark"]) .form-input:focus { |
| 257 | + border-color: rgb(var(--color-primary-500)); |
| 258 | + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2); |
| 259 | + } |
| 260 | +
|
| 261 | + .form-hint { |
| 262 | + font-size: 0.75rem; |
| 263 | + color: #6b7280; |
| 264 | + } |
| 265 | +
|
| 266 | + :global([data-mode="dark"]) .form-hint { |
| 267 | + color: var(--color-surface-400); |
| 268 | + } |
| 269 | +
|
| 270 | + .scope-info { |
| 271 | + display: flex; |
| 272 | + align-items: center; |
| 273 | + gap: 0.5rem; |
| 274 | + padding: 0.75rem 1rem; |
| 275 | + background: #f0f9ff; |
| 276 | + border: 1px solid #bae6fd; |
| 277 | + border-radius: 6px; |
| 278 | + font-size: 0.875rem; |
| 279 | + color: #0369a1; |
| 280 | + } |
| 281 | +
|
| 282 | + :global([data-mode="dark"]) .scope-info { |
| 283 | + background: rgba(14, 165, 233, 0.1); |
| 284 | + border-color: rgba(14, 165, 233, 0.3); |
| 285 | + color: rgb(var(--color-primary-300)); |
| 286 | + } |
| 287 | +</style> |
0 commit comments