@nymphjs/tilmeld-components 1.0.0-beta.13 → 1.0.0-beta.131

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,11 +1,13 @@
1
- {#if clientConfig != null && clientConfig.pwRecovery}
1
+ <svelte:options runes />
2
+
3
+ {#if $clientConfig != null && $clientConfig.pwRecovery}
2
4
  <Dialog
3
- use={usePass}
5
+ {use}
4
6
  bind:open
5
7
  aria-labelledby="tilmeld-recovery-title"
6
8
  aria-describedby="tilmeld-recovery-content"
7
9
  surface$class="tilmeld-recover-dialog-surface"
8
- {...exclude($$restProps, [
10
+ {...exclude(restProps, [
9
11
  'recoveryTypePassword$',
10
12
  'recoveryTypeUsername$',
11
13
  'account$',
@@ -27,23 +29,27 @@
27
29
  {successRecoveredMessage}
28
30
  {:else}
29
31
  {#if !hasSentSecret}
30
- {#if !clientConfig.emailUsernames}
32
+ {#if !$clientConfig.emailUsernames}
31
33
  <div>
32
34
  <FormField style="margin-right: 1em;">
33
35
  <Radio
34
36
  bind:group={recoveryType}
35
37
  value="password"
36
- {...prefixFilter($$restProps, 'recoveryTypePassword$')}
38
+ {...prefixFilter(restProps, 'recoveryTypePassword$')}
37
39
  />
38
- <span slot="label">I don't know my password.</span>
40
+ {#snippet label()}
41
+ I don't know my password.
42
+ {/snippet}
39
43
  </FormField>
40
44
  <FormField style="margin-right: 1em;">
41
45
  <Radio
42
46
  bind:group={recoveryType}
43
47
  value="username"
44
- {...prefixFilter($$restProps, 'recoveryTypeUsername$')}
48
+ {...prefixFilter(restProps, 'recoveryTypeUsername$')}
45
49
  />
46
- <span slot="label">I don't know my username.</span>
50
+ {#snippet label()}
51
+ I don't know my username.
52
+ {/snippet}
47
53
  </FormField>
48
54
  </div>
49
55
  {/if}
@@ -51,7 +57,7 @@
51
57
  <div>
52
58
  {#if recoveryType === 'password'}
53
59
  <p>
54
- To reset your password, type the {clientConfig.emailUsernames
60
+ To reset your password, type the {$clientConfig.emailUsernames
55
61
  ? 'email'
56
62
  : 'username'}
57
63
  you use to sign in below.
@@ -69,28 +75,28 @@
69
75
  <Textfield
70
76
  bind:this={accountElem}
71
77
  bind:value={account}
72
- label={clientConfig.emailUsernames || recoveryType === 'username'
78
+ label={$clientConfig.emailUsernames || recoveryType === 'username'
73
79
  ? 'Email Address'
74
80
  : 'Username'}
75
- type={clientConfig.emailUsernames || recoveryType === 'username'
81
+ type={$clientConfig.emailUsernames || recoveryType === 'username'
76
82
  ? 'email'
77
83
  : 'text'}
78
- input$autocomplete={clientConfig.emailUsernames ||
84
+ input$autocomplete={$clientConfig.emailUsernames ||
79
85
  recoveryType === 'username'
80
86
  ? 'email'
81
87
  : 'username'}
82
88
  input$autocapitalize="off"
83
89
  input$spellcheck="false"
84
- {...prefixFilter($$restProps, 'account$')}
90
+ {...prefixFilter(restProps, 'account$')}
85
91
  />
86
92
  </div>
87
93
 
88
94
  {#if recoveryType === 'password'}
89
95
  <div class="tilmeld-recover-action">
90
96
  <a
91
- href="javascript:void(0);"
92
- on:click={() => (hasSentSecret = 1)}
93
- {...prefixFilter($$restProps, 'alreadyGotCodeLink$')}
97
+ href={'javascript:void(0);'}
98
+ onclick={() => (hasSentSecret = 1)}
99
+ {...prefixFilter(restProps, 'alreadyGotCodeLink$')}
94
100
  >
95
101
  Already Got a Code?
96
102
  </a>
@@ -98,7 +104,7 @@
98
104
  {/if}
99
105
  {:else}
100
106
  <div>
101
- <p {...prefixFilter($$restProps, 'codeSentMessage$')}>
107
+ <p {...prefixFilter(restProps, 'codeSentMessage$')}>
102
108
  A code has been sent to you by email. Enter that code here, and a
103
109
  new password for your account.
104
110
  </p>
@@ -109,16 +115,16 @@
109
115
  <Textfield
110
116
  bind:this={accountElem}
111
117
  bind:value={account}
112
- label={clientConfig.emailUsernames
118
+ label={$clientConfig.emailUsernames
113
119
  ? 'Email Address'
114
120
  : 'Username'}
115
- type={clientConfig.emailUsernames ? 'email' : 'text'}
116
- input$autocomplete={clientConfig.emailUsernames
121
+ type={$clientConfig.emailUsernames ? 'email' : 'text'}
122
+ input$autocomplete={$clientConfig.emailUsernames
117
123
  ? 'email'
118
124
  : 'username'}
119
125
  input$autocapitalize="off"
120
126
  input$spellcheck="false"
121
- {...prefixFilter($$restProps, 'account$')}
127
+ {...prefixFilter(restProps, 'account$')}
122
128
  />
123
129
  </div>
124
130
  {/if}
@@ -129,7 +135,7 @@
129
135
  label="Recovery Code"
130
136
  type="text"
131
137
  input$autocomplete="one-time-code"
132
- {...prefixFilter($$restProps, 'recoveryCode$')}
138
+ {...prefixFilter(restProps, 'recoveryCode$')}
133
139
  />
134
140
  </div>
135
141
 
@@ -139,7 +145,7 @@
139
145
  label="Password"
140
146
  type="password"
141
147
  input$autocomplete="new-password"
142
- {...prefixFilter($$restProps, 'password$')}
148
+ {...prefixFilter(restProps, 'password$')}
143
149
  />
144
150
  </div>
145
151
 
@@ -149,15 +155,15 @@
149
155
  label="Re-enter Password"
150
156
  type="password"
151
157
  input$autocomplete="new-password"
152
- {...prefixFilter($$restProps, 'password2$')}
158
+ {...prefixFilter(restProps, 'password2$')}
153
159
  />
154
160
  </div>
155
161
 
156
162
  <div class="tilmeld-recover-action">
157
163
  <a
158
- href="javascript:void(0);"
159
- on:click={() => (hasSentSecret = false)}
160
- {...prefixFilter($$restProps, 'needCodeLink$')}
164
+ href={'javascript:void(0);'}
165
+ onclick={() => (hasSentSecret = false)}
166
+ {...prefixFilter(restProps, 'needCodeLink$')}
161
167
  >
162
168
  Need a New Code?
163
169
  </a>
@@ -170,35 +176,35 @@
170
176
  </div>
171
177
  {/if}
172
178
 
173
- {#if recovering}
179
+ {#if loading}
174
180
  <div class="tilmeld-recover-loading">
175
181
  <CircularProgress
176
182
  style="height: 24px; width: 24px;"
177
183
  indeterminate
178
- {...prefixFilter($$restProps, 'progress$')}
184
+ {...prefixFilter(restProps, 'progress$')}
179
185
  />
180
186
  </div>
181
187
  {/if}
182
188
  {/if}
183
189
  </Content>
184
190
  <Actions>
185
- <Button on:click={() => (open = false)} disabled={recovering}>
191
+ <Button onclick={() => (open = false)} disabled={loading}>
186
192
  <Label>{successRecoveredMessage ? 'Close' : 'Cancel'}</Label>
187
193
  </Button>
188
194
  {#if !successRecoveredMessage}
189
195
  {#if !hasSentSecret}
190
196
  <Button
191
- on:click$preventDefault$stopPropagation={sendRecovery}
192
- disabled={recovering}
193
- {...prefixFilter($$restProps, 'sendCodeButton$')}
197
+ onclick={preventDefault(stopPropagation(sendRecovery))}
198
+ disabled={loading}
199
+ {...prefixFilter(restProps, 'sendCodeButton$')}
194
200
  >
195
201
  <Label>Send Recovery</Label>
196
202
  </Button>
197
203
  {:else}
198
204
  <Button
199
- on:click$preventDefault$stopPropagation={recover}
200
- disabled={recovering}
201
- {...prefixFilter($$restProps, 'resetPasswordButton$')}
205
+ onclick={preventDefault(stopPropagation(recover))}
206
+ disabled={loading}
207
+ {...prefixFilter(restProps, 'resetPasswordButton$')}
202
208
  >
203
209
  <Label>Reset Password</Label>
204
210
  </Button>
@@ -209,8 +215,10 @@
209
215
  {/if}
210
216
 
211
217
  <script lang="ts">
218
+ import type { ComponentProps } from 'svelte';
212
219
  import { onMount } from 'svelte';
213
- import { get_current_component } from 'svelte/internal';
220
+ import type { Writable } from 'svelte/store';
221
+ import { writable } from 'svelte/store';
214
222
  import CircularProgress from '@smui/circular-progress';
215
223
  import Dialog, { Title, Content, Actions } from '@smui/dialog';
216
224
  import Textfield from '@smui/textfield';
@@ -218,53 +226,147 @@
218
226
  import FormField from '@smui/form-field';
219
227
  import Radio from '@smui/radio';
220
228
  import type { ActionArray } from '@smui/common/internal';
221
- import {
222
- forwardEventsBuilder,
223
- exclude,
224
- prefixFilter,
225
- } from '@smui/common/internal';
229
+ import { exclude, prefixFilter } from '@smui/common/internal';
230
+ import { preventDefault, stopPropagation } from '@smui/common/events';
231
+ import type { SmuiElementPropMap } from '@smui/common';
226
232
  import type {
227
233
  User as UserClass,
228
234
  ClientConfig,
229
235
  } from '@nymphjs/tilmeld-client';
230
236
 
231
- const forwardEvents = forwardEventsBuilder(get_current_component());
232
-
233
- export let use: ActionArray = [];
234
- $: usePass = [forwardEvents, ...use] as ActionArray;
235
- export let open = false;
236
- export let title = 'Recover Your Account';
237
- export let clientConfig: ClientConfig | undefined = undefined;
238
- export let User: typeof UserClass;
239
-
240
- // Give focus to the account box when the form is ready.
241
- export let autofocus = true;
242
- export let recoveryType: 'username' | 'password' = 'password';
237
+ type OwnProps = {
238
+ /**
239
+ * An array of Action or [Action, ActionProps] to be applied to the element.
240
+ */
241
+ use?: ActionArray;
242
+ /**
243
+ * Whether the dialog is open.
244
+ */
245
+ open?: boolean;
246
+ /**
247
+ * The title of the dialog.
248
+ */
249
+ title?: string;
250
+ /**
251
+ * A writable store of the Nymph client config.
252
+ *
253
+ * It will be retrieved from the server if not provided.
254
+ */
255
+ clientConfig?: Writable<ClientConfig | undefined>;
256
+ /**
257
+ * The User class from Nymph.
258
+ */
259
+ User: typeof UserClass;
260
+ /**
261
+ * Give focus to the account box when the form is ready.
262
+ */
263
+ autofocus?: boolean;
264
+ /**
265
+ * The type of recovery being requested.
266
+ *
267
+ * User provided. You can bind to it if you need to.
268
+ */
269
+ recoveryType?: 'username' | 'password';
270
+ /**
271
+ * User provided. You can bind to it if you need to.
272
+ */
273
+ account?: string;
274
+ /**
275
+ * User provided. You can bind to it if you need to.
276
+ */
277
+ secret?: string;
278
+ /**
279
+ * User provided. You can bind to it if you need to.
280
+ */
281
+ password?: string;
282
+ /**
283
+ * User provided. You can bind to it if you need to.
284
+ */
285
+ password2?: string;
286
+ };
287
+ let {
288
+ use = [],
289
+ open = $bindable(false),
290
+ title = 'Recover Your Account',
291
+ clientConfig = $bindable(writable(false as unknown as undefined)),
292
+ User,
293
+ autofocus = true,
294
+ recoveryType = $bindable('password'),
295
+ account = $bindable(''),
296
+ secret = $bindable(''),
297
+ password = $bindable(''),
298
+ password2 = $bindable(''),
299
+ ...restProps
300
+ }: OwnProps & {
301
+ [
302
+ k in keyof ComponentProps<typeof Radio> as `recoveryTypePassword\$${k}`
303
+ ]?: ComponentProps<typeof Radio>[k];
304
+ } & {
305
+ [
306
+ k in keyof ComponentProps<typeof Radio> as `recoveryTypeUsername\$${k}`
307
+ ]?: ComponentProps<typeof Radio>[k];
308
+ } & {
309
+ [
310
+ k in keyof ComponentProps<typeof Textfield> as `account\$${k}`
311
+ ]?: ComponentProps<typeof Textfield>[k];
312
+ } & {
313
+ [
314
+ k in keyof SmuiElementPropMap['a'] as `alreadyGotCodeLink\$${k}`
315
+ ]?: SmuiElementPropMap['a'][k];
316
+ } & {
317
+ [
318
+ k in keyof SmuiElementPropMap['p'] as `codeSentMessage\$${k}`
319
+ ]?: SmuiElementPropMap['p'][k];
320
+ } & {
321
+ [
322
+ k in keyof ComponentProps<typeof Textfield> as `recoveryCode\$${k}`
323
+ ]?: ComponentProps<typeof Textfield>[k];
324
+ } & {
325
+ [
326
+ k in keyof ComponentProps<typeof Textfield> as `password\$${k}`
327
+ ]?: ComponentProps<typeof Textfield>[k];
328
+ } & {
329
+ [
330
+ k in keyof ComponentProps<typeof Textfield> as `password2\$${k}`
331
+ ]?: ComponentProps<typeof Textfield>[k];
332
+ } & {
333
+ [
334
+ k in keyof SmuiElementPropMap['a'] as `needCodeLink\$${k}`
335
+ ]?: SmuiElementPropMap['a'][k];
336
+ } & {
337
+ [
338
+ k in keyof ComponentProps<typeof CircularProgress> as `progress\$${k}`
339
+ ]?: ComponentProps<typeof CircularProgress>[k];
340
+ } & {
341
+ [
342
+ k in keyof ComponentProps<
343
+ typeof Button<undefined, 'button'>
344
+ > as `sendCodeButton\$${k}`
345
+ ]?: ComponentProps<typeof Button<undefined, 'button'>>[k];
346
+ } & {
347
+ [
348
+ k in keyof ComponentProps<
349
+ typeof Button<undefined, 'button'>
350
+ > as `resetPasswordButton\$${k}`
351
+ ]?: ComponentProps<typeof Button<undefined, 'button'>>[k];
352
+ } = $props();
243
353
 
244
- /** User provided. You can bind to it if you need to. */
245
- export let account = '';
246
- /** User provided. You can bind to it if you need to. */
247
- export let secret = '';
248
- /** User provided. You can bind to it if you need to. */
249
- export let password = '';
250
- /** User provided. You can bind to it if you need to. */
251
- export let password2 = '';
354
+ let loading = $state(false);
355
+ let hasSentSecret: number | boolean = $state(false);
356
+ let accountElem: Textfield | undefined = $state();
357
+ let failureMessage: string | undefined = $state();
358
+ let successRecoveredMessage: string | undefined = $state();
252
359
 
253
- let recovering = false;
254
- let hasSentSecret: number | boolean = false;
255
- let accountElem: Textfield;
256
- let failureMessage: string | undefined = undefined;
257
- let successRecoveredMessage: string | undefined = undefined;
258
-
259
- $: {
360
+ $effect(() => {
260
361
  if (open && autofocus && accountElem) {
261
362
  accountElem.focus();
262
363
  }
263
- }
364
+ });
264
365
 
265
366
  onMount(async () => {
266
- if (clientConfig === undefined) {
267
- clientConfig = await User.getClientConfig();
367
+ if ($clientConfig === (false as unknown as undefined)) {
368
+ $clientConfig = undefined;
369
+ $clientConfig = await User.getClientConfig();
268
370
  }
269
371
  });
270
372
 
@@ -272,7 +374,7 @@
272
374
  if (account === '') {
273
375
  failureMessage =
274
376
  'You need to enter ' +
275
- (clientConfig?.emailUsernames || recoveryType === 'username'
377
+ ($clientConfig?.emailUsernames || recoveryType === 'username'
276
378
  ? 'an email address'
277
379
  : 'a username') +
278
380
  '.';
@@ -280,7 +382,7 @@
280
382
  }
281
383
 
282
384
  failureMessage = undefined;
283
- recovering = true;
385
+ loading = true;
284
386
 
285
387
  try {
286
388
  const data = await User.sendRecovery({
@@ -299,14 +401,14 @@
299
401
  } catch (e: any) {
300
402
  failureMessage = e?.message;
301
403
  }
302
- recovering = false;
404
+ loading = false;
303
405
  }
304
406
 
305
407
  async function recover() {
306
408
  if (account === '') {
307
409
  failureMessage =
308
410
  'You need to enter ' +
309
- (clientConfig?.emailUsernames || recoveryType === 'username'
411
+ ($clientConfig?.emailUsernames || recoveryType === 'username'
310
412
  ? 'an email address'
311
413
  : 'a username') +
312
414
  '.';
@@ -322,7 +424,7 @@
322
424
  }
323
425
 
324
426
  failureMessage = undefined;
325
- recovering = true;
427
+ loading = true;
326
428
  try {
327
429
  const data = await User.recover({
328
430
  username: account,
@@ -337,7 +439,7 @@
337
439
  } catch (e: any) {
338
440
  failureMessage = e?.message;
339
441
  }
340
- recovering = false;
442
+ loading = false;
341
443
  }
342
444
  </script>
343
445
 
@@ -0,0 +1,236 @@
1
+ <svelte:options runes />
2
+
3
+ {#if $user != null}
4
+ <Dialog
5
+ {use}
6
+ bind:open
7
+ aria-labelledby="tilmeld-revoke-tokens-title"
8
+ aria-describedby="tilmeld-revoke-tokens-content"
9
+ surface$class="tilmeld-revoke-tokens-dialog-surface"
10
+ {...exclude(restProps, [
11
+ 'password$',
12
+ 'closeButton$',
13
+ 'saveButton$',
14
+ 'progress$',
15
+ ])}
16
+ >
17
+ <!-- Title cannot contain leading whitespace due to mdc-typography-baseline-top() -->
18
+ <Title id="tilmeld-revoke-tokens-title">{title}</Title>
19
+ <Content id="tilmeld-revoke-tokens-content">
20
+ <div>
21
+ {description}
22
+ </div>
23
+
24
+ <div style="margin-top: 1em;">
25
+ <Textfield
26
+ bind:value={password}
27
+ label="Password"
28
+ type="password"
29
+ style="width: 100%;"
30
+ input$autocomplete="current-password"
31
+ {...prefixFilter(restProps, 'password$')}
32
+ />
33
+ </div>
34
+
35
+ {@render additional?.()}
36
+
37
+ {#if failureMessage}
38
+ <div class="tilmeld-revoke-tokens-failure">
39
+ {failureMessage}
40
+ </div>
41
+ {/if}
42
+
43
+ {#if loading}
44
+ <div class="tilmeld-revoke-tokens-loading">
45
+ <CircularProgress
46
+ style="height: 24px; width: 24px;"
47
+ indeterminate
48
+ {...prefixFilter(restProps, 'progress$')}
49
+ />
50
+ </div>
51
+ {/if}
52
+ </Content>
53
+ <Actions>
54
+ <Button disabled={loading} {...prefixFilter(restProps, 'closeButton$')}>
55
+ <Label>Close</Label>
56
+ </Button>
57
+ <Button
58
+ onclick={preventDefault(stopPropagation(revokeTokens))}
59
+ disabled={loading}
60
+ {...prefixFilter(restProps, 'saveButton$')}
61
+ >
62
+ <Label>Log Out Other Sessions</Label>
63
+ </Button>
64
+ </Actions>
65
+ </Dialog>
66
+ {/if}
67
+
68
+ <script lang="ts">
69
+ import type { ComponentProps, Snippet } from 'svelte';
70
+ import { onMount, onDestroy } from 'svelte';
71
+ import type { Writable } from 'svelte/store';
72
+ import { writable } from 'svelte/store';
73
+ import CircularProgress from '@smui/circular-progress';
74
+ import Dialog, { Title, Content, Actions } from '@smui/dialog';
75
+ import Textfield from '@smui/textfield';
76
+ import Button, { Label } from '@smui/button';
77
+ import type { ActionArray } from '@smui/common/internal';
78
+ import { exclude, prefixFilter } from '@smui/common/internal';
79
+ import { preventDefault, stopPropagation } from '@smui/common/events';
80
+ import type { CurrentUserData } from '@nymphjs/tilmeld-client';
81
+ import type { User as UserClass } from '@nymphjs/tilmeld-client';
82
+
83
+ type OwnProps = {
84
+ /**
85
+ * An array of Action or [Action, ActionProps] to be applied to the element.
86
+ */
87
+ use?: ActionArray;
88
+ /**
89
+ * Whether the dialog is open.
90
+ */
91
+ open?: boolean;
92
+ /**
93
+ * The title of the dialog.
94
+ */
95
+ title?: string;
96
+ /**
97
+ * The description of the action given to the user.
98
+ */
99
+ description?: string;
100
+ /**
101
+ * The User class from Nymph.
102
+ */
103
+ User: typeof UserClass;
104
+ /**
105
+ * A writable store of the current user.
106
+ *
107
+ * It will be retrieved from the server if not provided.
108
+ */
109
+ user?: Writable<(UserClass & CurrentUserData) | null | undefined>;
110
+ /**
111
+ * User provided. You can bind to it if you need to.
112
+ */
113
+ password?: string;
114
+
115
+ /**
116
+ * A spot for additional content.
117
+ */
118
+ additional?: Snippet;
119
+ };
120
+ let {
121
+ use = [],
122
+ open = $bindable(false),
123
+ title = 'Log Out of Other Sessions',
124
+ description = 'This will log you out of all other sessions. You can use this if you think your account has been compromised. You will need to log in again on your other devices.',
125
+ User,
126
+ user = $bindable(writable(false as unknown as undefined)),
127
+ password = $bindable(''),
128
+ additional,
129
+ ...restProps
130
+ }: OwnProps & {
131
+ [
132
+ k in keyof ComponentProps<typeof Textfield> as `password\$${k}`
133
+ ]?: ComponentProps<typeof Textfield>[k];
134
+ } & {
135
+ [
136
+ k in keyof ComponentProps<typeof CircularProgress> as `progress\$${k}`
137
+ ]?: ComponentProps<typeof CircularProgress>[k];
138
+ } & {
139
+ [
140
+ k in keyof ComponentProps<
141
+ typeof Button<undefined, 'button'>
142
+ > as `closeButton\$${k}`
143
+ ]?: ComponentProps<typeof Button<undefined, 'button'>>[k];
144
+ } & {
145
+ [
146
+ k in keyof ComponentProps<
147
+ typeof Button<undefined, 'button'>
148
+ > as `saveButton\$${k}`
149
+ ]?: ComponentProps<typeof Button<undefined, 'button'>>[k];
150
+ } = $props();
151
+
152
+ let loading = $state(false);
153
+ let failureMessage: string | undefined = $state();
154
+
155
+ $effect(() => {
156
+ if (!open) {
157
+ loading = false;
158
+ failureMessage = undefined;
159
+ password = '';
160
+ }
161
+ });
162
+
163
+ const onLogin = (currentUser: UserClass & CurrentUserData) => {
164
+ $user = currentUser;
165
+ };
166
+ const onLogout = () => {
167
+ $user = null;
168
+ };
169
+
170
+ onMount(async () => {
171
+ User.on('login', onLogin);
172
+ User.on('logout', onLogout);
173
+ if ($user === (false as unknown as undefined)) {
174
+ $user = undefined;
175
+ $user = await User.current();
176
+ }
177
+ });
178
+
179
+ onDestroy(() => {
180
+ User.off('login', onLogin);
181
+ User.off('logout', onLogout);
182
+ });
183
+
184
+ async function revokeTokens() {
185
+ if (password === '') {
186
+ failureMessage = 'You need to enter your password';
187
+ return;
188
+ }
189
+
190
+ failureMessage = undefined;
191
+ loading = true;
192
+
193
+ // Get the current user again, in case their data has changed.
194
+ $user = await User.current();
195
+
196
+ if ($user == null) {
197
+ failureMessage = 'You must be logged in.';
198
+ loading = false;
199
+ return;
200
+ }
201
+
202
+ try {
203
+ // Revoke the current tokens.
204
+ const data = await $user.$revokeCurrentTokens({
205
+ password,
206
+ });
207
+
208
+ if (!data.result) {
209
+ failureMessage = data.message;
210
+ } else {
211
+ open = false;
212
+ }
213
+ } catch (e: any) {
214
+ failureMessage = e?.message;
215
+ }
216
+ loading = false;
217
+ }
218
+ </script>
219
+
220
+ <style>
221
+ :global(
222
+ .mdc-dialog .mdc-dialog__surface.tilmeld-revoke-tokens-dialog-surface
223
+ ) {
224
+ width: 360px;
225
+ max-width: calc(100vw - 32px);
226
+ }
227
+ .tilmeld-revoke-tokens-failure {
228
+ margin-top: 1em;
229
+ color: var(--mdc-theme-error, #f00);
230
+ }
231
+ .tilmeld-revoke-tokens-loading {
232
+ display: flex;
233
+ justify-content: center;
234
+ align-items: center;
235
+ }
236
+ </style>