diff options
| author | Adam Soltys <[email protected]> | 2022-11-09 14:26:05 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2022-11-09 14:26:05 -0800 |
| commit | 2be0c31d324e312f7d0b59e910d864d6a1ae99ff (patch) | |
| tree | 8ca8d3af860f371c256df2c1c1e087acbc1841ba /src | |
| parent | 692ffd2b6819f6254f77f819a4072eae61a1d638 (diff) | |
| parent | c31cfed30e022acf1c58d8594a1027524f3079da (diff) | |
| download | coinos-ui-2be0c31d324e312f7d0b59e910d864d6a1ae99ff.tar.gz coinos-ui-2be0c31d324e312f7d0b59e910d864d6a1ae99ff.zip | |
Merge branch 'master' into maven
Diffstat (limited to 'src')
21 files changed, 158 insertions, 143 deletions
diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte index ec0f5174..728b025a 100644 --- a/src/components/AppHeader.svelte +++ b/src/components/AppHeader.svelte @@ -17,7 +17,7 @@ menuButtons = [ { key: 'nav.profile', icon: 'profile', href: `/${user.username}` }, { key: 'nav.settings', icon: 'settings', href: `/${user.username}/settings` }, - { key: 'nav.support', icon: 'support', href: `/${user.username}/support` }, + { key: 'nav.support', icon: 'support', href: `/support` }, { key: 'nav.signOut', icon: 'logout', href: `/logout` } ]; @@ -80,7 +80,7 @@ class="bg-white p-2 rounded-full w-12 h-12 drop-shadow-xl border border-black/10 {$page .url.pathname === `/${user.username}` || $page.url.pathname === `/${user.username}/settings` || - $page.url.pathname === `/${user.username}/support` + $page.url.pathname === `/support` ? 'opacity-100' : `opacity-70 hover:opacity-80 ${showMenu ? 'opacity-80' : ''}`}" on:click={() => (showMenu = !showMenu)} diff --git a/src/components/Footer.svelte b/src/components/Footer.svelte index 8ef97e65..bf8b8810 100644 --- a/src/components/Footer.svelte +++ b/src/components/Footer.svelte @@ -10,7 +10,7 @@ const companyLinks = [ { url: '/news', titleID: 'news' }, - { url: 'mailto:[email protected]', titleID: 'support' }, + { url: '/support', titleID: 'support' }, { url: '/jobs', titleID: 'jobs' } ]; </script> diff --git a/src/components/Numpad.svelte b/src/components/Numpad.svelte index 55ce96d4..4f546499 100644 --- a/src/components/Numpad.svelte +++ b/src/components/Numpad.svelte @@ -1,7 +1,7 @@ <script> import { Left, Icon } from '$comp'; import { selectedRate } from '$lib/store'; - import { f, s, post, warning, sats } from '$lib/utils'; + import { f, s, post, warning, sat, sats } from '$lib/utils'; import { t } from '$lib/translations'; export let amount, @@ -36,7 +36,7 @@ $: amountFiatConverted = f(amountSats * ($selectedRate / sats), currency); - $: amountSatsConverted = s(amountFiat / ($selectedRate / sats)); + $: amountSatsConverted = sat(amountFiat / ($selectedRate / sats)); const numPad = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', '<']; @@ -94,7 +94,7 @@ {fiat ? `${symbol}${amountFiat}` : '⚡️' + amountSatsFormatted} </div> <span class="text-secondary mr-1" - >{fiat ? `⚡️${amountSatsConverted}` : amountFiatConverted}</span + >{fiat ? amountSatsConverted : amountFiatConverted}</span > <button type="button" diff --git a/src/components/Pin.svelte b/src/components/Pin.svelte index 2a6bf977..80e003b9 100644 --- a/src/components/Pin.svelte +++ b/src/components/Pin.svelte @@ -1,5 +1,6 @@ <script> import { pin } from '$lib/store'; + let pinCode = ''; let pinInput; @@ -9,7 +10,7 @@ <div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-20"> <div class="relative top-1/3 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white space-y-5"> <h1 class="text-center text-2xl font-semibold">Please enter your PIN</h1> - <input bind:value={pinCode} /> + <input bind:value={pinCode} autofocus /> <div class="w-full flex"> <button type="submit" diff --git a/src/lib/socket.js b/src/lib/socket.js index 6678b979..8d84073c 100644 --- a/src/lib/socket.js +++ b/src/lib/socket.js @@ -36,11 +36,8 @@ export const messages = (data) => ({ async payment() { let { amount, invoice } = data; - if (invoice) { - invoices.set({ ...get(invoices), [invoice.uuid]: invoice }); - } - - if (get(user).account_id !== data.account_id) return; + if (invoice) invalidate('app:invoice'); + if (get(user)?.account_id !== data.account_id) return; let payments = get(txns); let i = payments.findIndex((p) => p.id === data.id); diff --git a/src/lib/utils.js b/src/lib/utils.js index 7e0b8e4f..2bf6b800 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -37,7 +37,10 @@ export const get = (url, headers = {}) => export const post = (url, body, headers) => { headers = { ...headers, 'content-type': 'application/json', accept: 'application/json' }; return fetch(base + url, { method: 'POST', body: JSON.stringify(body), headers }) - .then((r) => r.text()) + .then(async (r) => { + if (r.ok) return r.text(); + throw new Error(await r.text()); + }) .then((body) => { try { body = JSON.parse(body); @@ -67,7 +70,7 @@ export function reverseFormat(val, locale) { return Number.isNaN(reversedVal) ? 0 : +reversedVal; } -export let protectedRoutes = [/customers/, /dashboard/, /settings/, /transactions/, /support/]; +export let protectedRoutes = [/customers/, /dashboard/, /settings/, /transactions/]; export const success = (m) => { toast.pop(); diff --git a/src/routes/(app)/[username]/+page.svelte b/src/routes/(app)/[username]/+page.svelte index 960cf897..8afb5280 100644 --- a/src/routes/(app)/[username]/+page.svelte +++ b/src/routes/(app)/[username]/+page.svelte @@ -59,6 +59,12 @@ > </a> {/if} + + <a href={`/${subject.username}/address`}> + <button class="rounded-full border py-2 px-5 font-bold hover:opacity-80 w-full mb-2"> + Bitcoin address + </button> + </a> </div> {/if} </div> diff --git a/src/routes/(app)/[username]/dashboard/+page.svelte b/src/routes/(app)/[username]/dashboard/+page.svelte index 0ea0e0a8..43879fcb 100644 --- a/src/routes/(app)/[username]/dashboard/+page.svelte +++ b/src/routes/(app)/[username]/dashboard/+page.svelte @@ -48,7 +48,7 @@ </div> <div class="text-secondary text-2xl"> - {sat(user.account.balance)} + ⚡️{s(user.account.balance)} </div> <div class="grid sm:grid-cols-2 gap-2 mt-8"> diff --git a/src/routes/(app)/[username]/settings/+page.server.js b/src/routes/(app)/[username]/settings/[...tab]/+page.server.js index 482b70b1..dcaa26b4 100644 --- a/src/routes/(app)/[username]/settings/+page.server.js +++ b/src/routes/(app)/[username]/settings/[...tab]/+page.server.js @@ -1,5 +1,11 @@ -import { invalid } from '@sveltejs/kit'; +import { invalid, redirect } from '@sveltejs/kit'; import { auth, get, post } from '$lib/utils'; + +export function load({ params, url }) { + if (url.pathname.endsWith('settings')) throw redirect(307, url.pathname + '/account'); + return params; +} + export const actions = { default: async ({ cookies, locals, request }) => { let form = Object.fromEntries(await request.formData()); @@ -10,7 +16,7 @@ export const actions = { }; try { - await post(`/user`, user, auth(cookies)); + ({ user } = await post(`/user`, user, auth(cookies))); } catch (e) { return invalid(400, { message: e.message }); } diff --git a/src/routes/(app)/[username]/settings/+page.svelte b/src/routes/(app)/[username]/settings/[...tab]/+page.svelte index 250087c1..d546e817 100644 --- a/src/routes/(app)/[username]/settings/+page.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/+page.svelte @@ -2,31 +2,36 @@ import { onMount } from 'svelte'; import { fly } from 'svelte/transition'; import { enhance } from '$app/forms'; - import Account from './_account.svelte'; - import Pos from './_pos.svelte'; - import Security from './_security.svelte'; import { Icon, Spinner, Pin } from '$comp'; import { t } from '$lib/translations'; import { failure, success } from '$lib/utils'; import { avatarUpload, bannerUpload, pin } from '$lib/store'; import { upload } from '$lib/upload'; + import { page } from '$app/stores'; + + import Account from './_account.svelte'; + import Pos from './_pos.svelte'; + import Security from './_security.svelte'; export let data; export let form; - let { user, token } = data; + let submit; + + let { user, token, tab } = data; + $: update(data); - let update = () => ({ user, token } = data); + let update = () => ({ user, token, tab } = data); $: form?.user && ({ user } = form); - $: if (form?.message?.startsWith('Pin')) { - failure('Wrong pin, try again'); - $pin = ''; - } + $: form?.success && success('Settings saved!'); - let tab = 'account'; + // $: if (form?.message?.startsWith('Pin')) { + // failure('Wrong pin, try again'); + // $pin = ''; + // } let tabs = [ { name: 'account', key: 'ACCOUNT', comp: Account }, @@ -36,7 +41,7 @@ $: ({ comp } = tabs.find((t) => t.name === tab)); - let loading, submit; + let loading; let save = async (msg) => { loading = true; @@ -74,11 +79,11 @@ <div class="font-bold flex justify-between items-center border-b pb-3 text-secondary"> {#each tabs as { name, key }} - <button - class="hover:opacity-80" - class:text-black={tab === name} - on:click|preventDefault={() => (tab = name)}>{$t(`user.settings.${key}`)}</button - > + <a href={`/${user.username}/settings/${name}`}> + <button class="hover:opacity-80" class:text-black={tab === name} + >{$t(`user.settings.${key}`)}</button + > + </a> {/each} </div> diff --git a/src/routes/(app)/[username]/settings/_account.svelte b/src/routes/(app)/[username]/settings/[...tab]/_account.svelte index e49205ca..e49205ca 100644 --- a/src/routes/(app)/[username]/settings/_account.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/_account.svelte diff --git a/src/routes/(app)/[username]/settings/_pos.svelte b/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte index ccbeeff4..ccbeeff4 100644 --- a/src/routes/(app)/[username]/settings/_pos.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte diff --git a/src/routes/(app)/[username]/settings/_security.svelte b/src/routes/(app)/[username]/settings/[...tab]/_security.svelte index 4bdb00d4..0ffb7834 100644 --- a/src/routes/(app)/[username]/settings/_security.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/_security.svelte @@ -27,7 +27,11 @@ let otp; $: pinChange($current); let pinChange = async (pin) => { - otp = await post('/otpsecret', { pin }); + try { + otp = await post('/otpsecret', { pin }); + } catch (e) { + console.log(e); + } }; let locked; @@ -78,6 +82,7 @@ pin = null; submit.click(); } catch (e) { + console.log(e); failure('Failed to disable pin'); } } else { @@ -112,6 +117,7 @@ toggleDisabling(); } } catch (e) { + console.log(e); failure('Failed to disable 2FA, try again'); } }; diff --git a/src/routes/(app)/disable2fa/+server.js b/src/routes/(app)/disable2fa/+server.js index 237da445..13fcb2b9 100644 --- a/src/routes/(app)/disable2fa/+server.js +++ b/src/routes/(app)/disable2fa/+server.js @@ -1,8 +1,13 @@ +import { error } from '@sveltejs/kit'; import { auth, post } from '$lib/utils'; -export async function PUT({ cookies, request }) { - let body = await request.json(); - let res = await post('/disable2fa', body, auth(cookies)); +export async function POST({ cookies, request }) { + try { + let body = await request.json(); + let res = await post('/disable2fa', body, auth(cookies)); - return new Response(JSON.stringify(res)); + return new Response(JSON.stringify(res)); + } catch (e) { + throw error(500, 'Problem disabling 2fa'); + } } diff --git a/src/routes/(app)/invoice/[id]/+layout.server.js b/src/routes/(app)/invoice/[id]/+layout.server.js index 4b6cf97e..dacc44e6 100644 --- a/src/routes/(app)/invoice/[id]/+layout.server.js +++ b/src/routes/(app)/invoice/[id]/+layout.server.js @@ -1,9 +1,17 @@ import Qr from 'qrcode-base64'; import { get } from '$lib/utils'; +import { redirect } from '@sveltejs/kit'; + +export async function load({ depends, params, url }) { + depends('app:invoice'); -export async function load({ params }) { let { id } = params; let invoice = await get(`/invoice?uuid=${id}`); + let { amount, received, pending } = invoice; + + let paid = (!amount && (received || pending)) || (amount > 0 && received + pending >= amount); + if (paid && !url.pathname.endsWith('paid')) throw redirect(307, `/invoice/${id}/paid`); + let sm = Qr.drawImg(invoice.text, { size: 300 }); let lg = Qr.drawImg(invoice.text, { size: 1200 }); diff --git a/src/routes/(app)/invoice/[id]/+page.svelte b/src/routes/(app)/invoice/[id]/+page.svelte index dec33b62..569d1430 100644 --- a/src/routes/(app)/invoice/[id]/+page.svelte +++ b/src/routes/(app)/invoice/[id]/+page.svelte @@ -1,7 +1,7 @@ <script> import { send } from '$lib/socket'; import { back, copy, f, get, sat, reverseFormat, s, sats } from '$lib/utils'; - import { onMount, onDestroy } from 'svelte'; + import { tick, onMount, onDestroy } from 'svelte'; import { browser } from '$app/environment'; import { invoices, last } from '$lib/store'; import { Avatar, Icon, Heart, Image, Qr } from '$comp'; @@ -11,8 +11,6 @@ export let data; - let showQr; - $: refresh(data); let { invoice, id, user, sm, lg } = data; let { @@ -27,6 +25,8 @@ user: { username, currency } } = invoice; + let showQr = !amount; + let src = sm; let qr; @@ -49,14 +49,6 @@ tipPercent = (tip / amount) * 100; }; - $invoices[id] = { amount, id, rate, received, text, tip, username }; - $: browser && - $invoices[id].amount > 0 && - $invoices[id]?.received >= $invoices[id]?.amount && - goto(($invoices[id].memo === 'launch' && '/launch/purchase') || `/invoice/${id}/paid`); - - $: browser && $invoices[id].pending > 0 && goto(`/invoice/${id}/pending`); - $: amountFiat = parseFloat(((amount * rate) / sats).toFixed(2)); $: tipAmount = ((tip * rate) / sats).toFixed(2); @@ -88,7 +80,7 @@ <div class="container mx-auto max-w-lg px-4 space-y-5"> <div class="w-full flex"> <h1 class="text-secondary block text-2xl flex mx-auto"> - <div class="my-auto">Pay</div> + <div class="my-auto">Send to</div> <div> <a href="/{username}" class="text-black font-semibold hover:opacity-80 mx-auto"> @@ -107,6 +99,10 @@ <img {src} class:p-4={full} class="w-[300px] mx-auto" bind:this={qr} on:click={toggle} /> </div> + {#if address} + <div>{address}</div> + {/if} + <div class="mb-10 flex gap-2 justify-center"> <button class="flex rounded-full border py-2 px-5 font-bold hover:opacity-80 mb-2" diff --git a/src/routes/(app)/invoice/[id]/paid/+page.svelte b/src/routes/(app)/invoice/[id]/paid/+page.svelte index 4f0a8ed1..60bc4592 100644 --- a/src/routes/(app)/invoice/[id]/paid/+page.svelte +++ b/src/routes/(app)/invoice/[id]/paid/+page.svelte @@ -9,41 +9,55 @@ import { invoices } from '$lib/store'; export let data; - let { invoice } = data; - let { amount, currency, rate, tip } = invoice; + let amount, currency, rate, received, pending, tip, user, uuid; + $: data && ({ amount, currency, rate, received, pending, tip, user, uuid } = data.invoice); toast.pop(0); - $: amountFiat = parseFloat(((amount * rate) / sats).toFixed(2)); + $: amountFiat = parseFloat(((received * rate) / sats).toFixed(2)); + $: pendingFiat = parseFloat(((pending * rate) / sats).toFixed(2)); $: tipFiat = parseFloat(((tip * rate) / sats).toFixed(2)); - - const handleDoneClick = () => { - delete $invoices[invoice.uuid]; - goto(`/${invoice.user.username}/receive`); - }; </script> <div class="container px-4 text-center mx-auto"> <div class="flex w-full py-20 max-w-[200px] mx-auto" in:scale={{ start: 0.5 }}> <Icon icon="check" style="mx-auto" /> </div> - <h1 class="text-3xl md:text-4xl font-bold mb-6">{$t('invoice.paymentSuccessful')}</h1> - <h2 class="text-2xl md:text-3xl font-semibold"> - {f(amountFiat, currency)} - {#if tip} - + {f(tipFiat, currency)} - {/if} - </h2> - <h3 class="text-secondary md:text-lg mb-6 mt-1"> - {sat(amount)} - {#if tip} - +{sat(tip)} - {/if} - </h3> - <button - class="bg-black text-white rounded-2xl w-20 py-3 font-bold hover:opacity-80" - on:click={handleDoneClick} - > - {$t('invoice.done')} - </button> + {#if received} + <h1 class="text-3xl md:text-4xl font-bold mb-6">{$t('invoice.paymentSuccessful')}</h1> + <h2 class="text-2xl md:text-3xl font-semibold"> + {f(amountFiat, currency)} + {#if tip} + + {f(tipFiat, currency)} + {/if} + </h2> + <h3 class="text-secondary md:text-lg mb-6 mt-1"> + {sat(received)} + {#if tip} + +{sat(tip)} + {/if} + </h3> + {/if} + + {#if pending} + <h1 class="text-3xl md:text-4xl font-bold mb-6">Payment detected</h1> + <h2 class="text-2xl md:text-3xl font-semibold"> + {f(pendingFiat, currency)} + {#if tip} + + {f(tipFiat, currency)} + {/if} + </h2> + <h3 class="text-secondary md:text-lg mb-6 mt-1"> + {sat(pending)} + {#if tip} + +{sat(tip)} + {/if} + </h3> + {/if} + + <a href={`/${user.username}/receive`}> + <button class="bg-black text-white rounded-2xl w-20 py-3 font-bold hover:opacity-80"> + {$t('invoice.done')} + </button> + </a> </div> diff --git a/src/routes/(app)/invoice/[id]/pending/+page.svelte b/src/routes/(app)/invoice/[id]/pending/+page.svelte deleted file mode 100644 index d3970dab..00000000 --- a/src/routes/(app)/invoice/[id]/pending/+page.svelte +++ /dev/null @@ -1,56 +0,0 @@ -<script> - import { scale } from 'svelte/transition'; - import { Icon } from '$comp'; - import { toast } from '@zerodevx/svelte-toast'; - import { browser } from '$app/environment'; - import { t } from '$lib/translations'; - import { f, s, sat, sats } from '$lib/utils'; - import { goto } from '$app/navigation'; - import { invoices } from '$lib/store'; - - export let data; - let { invoice } = data; - let { pending, currency, rate, tip } = invoice; - - toast.pop(0); - - $: pendingFiat = parseFloat(((pending * rate) / sats).toFixed(2)); - $: tipFiat = parseFloat(((tip * rate) / sats).toFixed(2)); - - const handleDoneClick = () => { - delete $invoices[invoice.uuid]; - goto(`/${invoice.user.username}/receive`); - }; -</script> - -<div class="container px-4 text-center mx-auto space-y-5"> - <div class="flex w-full py-20 max-w-[200px] mx-auto" in:scale={{ start: 0.5 }}> - <Icon icon="check" style="mx-auto" /> - </div> - - <h1 class="text-3xl md:text-4xl font-bold">Payment detected</h1> - - <div> - <h2 class="text-2xl md:text-3xl font-semibold"> - {f(pendingFiat, currency)} - {#if tip} - + {f(tipFiat, currency)} - {/if} - </h2> - <h3 class="text-secondary md:text-lg mt-1"> - {sat(pending)} - {#if tip} - +{sat(tip)} - {/if} - </h3> - </div> - - <p class="text-xl text-red-600">Pending confirmation</p> - - <button - class="bg-black text-white rounded-2xl w-20 py-3 font-bold hover:opacity-80" - on:click={handleDoneClick} - > - {$t('invoice.done')} - </button> -</div> diff --git a/src/routes/(app)/otpsecret/+server.js b/src/routes/(app)/otpsecret/+server.js index 8dec7778..cdd050c8 100644 --- a/src/routes/(app)/otpsecret/+server.js +++ b/src/routes/(app)/otpsecret/+server.js @@ -1,8 +1,13 @@ import { auth, post } from '$lib/utils'; import Qr from 'qrcode-base64'; +import { error } from '@sveltejs/kit'; export async function POST({ cookies, locals, request }) { - let { secret } = await post('/otpsecret', await request.json(), auth(cookies)); - let uri = `otpauth://totp/coinos:${locals.user.username}?secret=${secret}&period=30&digits=6&algorithm=SHA1&issuer=coinos`; - return new Response(JSON.stringify({ secret, uri, qr: Qr.drawImg(uri, { size: 600 }) })); + try { + let { secret } = await post('/otpsecret', await request.json(), auth(cookies)); + let uri = `otpauth://totp/coinos:${locals.user.username}?secret=${secret}&period=30&digits=6&algorithm=SHA1&issuer=coinos`; + return new Response(JSON.stringify({ secret, uri, qr: Qr.drawImg(uri, { size: 600 }) })); + } catch (e) { + throw new error(500, 'Problem saving secret'); + } } diff --git a/src/routes/(app)/[username]/support/+page.server.js b/src/routes/(app)/support/+page.server.js index a335ec96..78c640e3 100644 --- a/src/routes/(app)/[username]/support/+page.server.js +++ b/src/routes/(app)/support/+page.server.js @@ -1,3 +1,6 @@ +import { post } from "$lib/utils"; +import { invalid } from '@sveltejs/kit'; + export const actions = { default: async ({ cookies, request }) => { let form = Object.fromEntries(await request.formData()); @@ -5,7 +8,7 @@ export const actions = { try { await post('/email', form); } catch (e) { - return invalid(400, { failed: true }); + return invalid(400, { error: e.message }); } return { success: true }; diff --git a/src/routes/(app)/[username]/support/+page.svelte b/src/routes/(app)/support/+page.svelte index cd1cc69f..690e4770 100644 --- a/src/routes/(app)/[username]/support/+page.svelte +++ b/src/routes/(app)/support/+page.svelte @@ -1,22 +1,36 @@ <script> import { enhance } from '$app/forms'; import { scale } from 'svelte/transition'; - import { Icon } from '$comp'; + import { AppHeader, Icon } from '$comp'; import { t } from '$lib/translations'; export let data, form; let { user } = data; + $: if (user) { + data.subject = { ...user }; + } + let email; let message; </script> -<div class="container px-4 max-w-lg mx-auto mt-20"> +{#if user} + <AppHeader {data} /> +{/if} + +{#if form?.error} + <div class="text-red-600 text-center"> + {form.error} + </div> +{/if} + +<div class="container px-4 max-w-lg mx-auto mt-20 space-y-5"> {#if form?.success} <h1 class="text-center text-3xl md:text-4xl font-semibold mb-8">Thank you!</h1> <p class="text-center mb-8">Someone will be in touch shortly.</p> - <a href={`/${user.username}/dashboard`}> + <a href={user ? `/${user.username}/dashboard` : '/'}> <button class="rounded-full border py-2 px-5 font-bold hover:opacity-80 w-full mb-2" >Done</button > @@ -25,6 +39,9 @@ <h1 class="text-center text-3xl md:text-4xl font-semibold mb-8"> {$t('user.support.header')} </h1> + + <p class="text-secondary">Fill out this form or email us directly at <a class="underline" href="mailto:[email protected]">[email protected]</a> and we'll do our best to get back to you in a timely manner.</p> + <form method="POST" use:enhance> <div class="mb-4"> <label for="account" class="font-semibold">{$t('user.support.accountName')}</label> @@ -33,8 +50,7 @@ type="text" name="account" required - disabled - value={user.username} + value={user?.username || ''} /> </div> |
