mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2026-01-04 14:54:24 +01:00
settings save kind of works
This commit is contained in:
@@ -49,10 +49,7 @@ export default function BalanceBox() {
|
||||
</Show>
|
||||
</Suspense>
|
||||
</FancyCard>
|
||||
<div class="flex gap-2 py-4">
|
||||
<ButtonLink href="/send" intent="green">Send</ButtonLink>
|
||||
<ButtonLink href="/receive" intent="blue">Receive</ButtonLink>
|
||||
</div>
|
||||
|
||||
<FancyCard title="On-Chain" tag={onChainBalance.loading && <SyncingIndicator />}>
|
||||
<Suspense fallback={<Amount amountSats={0} showFiat loading={true} />}>
|
||||
<div onClick={refetchBalance}>
|
||||
@@ -72,6 +69,10 @@ export default function BalanceBox() {
|
||||
</Show>
|
||||
</Suspense>
|
||||
</FancyCard>
|
||||
<div class="flex gap-2 py-4">
|
||||
<ButtonLink href="/send" intent="green">Send</ButtonLink>
|
||||
<ButtonLink href="/receive" intent="blue">Receive</ButtonLink>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ const OVERLAY = "fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"
|
||||
const DIALOG_POSITIONER = "fixed inset-0 z-50 flex items-center justify-center"
|
||||
const DIALOG_CONTENT = "w-[80vw] max-w-[400px] p-4 bg-gray/50 backdrop-blur-md shadow-xl rounded-xl border border-white/10"
|
||||
|
||||
// TODO: implement this like toast so it's just one global confirm and I can call it with `confirm({ title: "Are you sure?", description: "This will delete your node" })`
|
||||
export const ConfirmDialog: ParentComponent<{ isOpen: boolean; loading: boolean; onCancel: () => void, onConfirm: () => void }> = (props) => {
|
||||
return (
|
||||
<Dialog.Root isOpen={props.isOpen} onOpenChange={props.onCancel}>
|
||||
|
||||
97
src/components/SettingsStringsEditor.tsx
Normal file
97
src/components/SettingsStringsEditor.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import { createForm, url } from '@modular-forms/solid';
|
||||
import { TextField } from '~/components/layout/TextField';
|
||||
import { NodeManagerSettingStrings, getExistingSettings } from '~/logic/nodeManagerSetup';
|
||||
import { Button } from '~/components/layout';
|
||||
import { createSignal } from 'solid-js';
|
||||
import { deleteDb } from '~/routes/Settings';
|
||||
import { showToast } from './Toaster';
|
||||
import eify from '~/utils/eify';
|
||||
import { ConfirmDialog } from "~/components/Dialog";
|
||||
import { useMegaStore } from '~/state/megaStore';
|
||||
|
||||
export function SettingsStringsEditor() {
|
||||
const existingSettings = getExistingSettings();
|
||||
const [settingsForm, { Form, Field, FieldArray }] = createForm<NodeManagerSettingStrings>({ initialValues: existingSettings });
|
||||
const [confirmOpen, setConfirmOpen] = createSignal(false);
|
||||
|
||||
const [settingsTemp, setSettingsTemp] = createSignal<NodeManagerSettingStrings>();
|
||||
|
||||
const [state, actions] = useMegaStore();
|
||||
|
||||
async function handleSubmit(values: NodeManagerSettingStrings) {
|
||||
try {
|
||||
const existing = getExistingSettings();
|
||||
const newSettings = { ...existing, ...values }
|
||||
if (existing.network !== values.network) {
|
||||
// If the network changes we need to confirm the wipe
|
||||
// Save the settings so we can get them later
|
||||
setSettingsTemp(newSettings);
|
||||
setConfirmOpen(true);
|
||||
} else {
|
||||
await actions.setupNodeManager(newSettings);
|
||||
window.location.reload();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
showToast(eify(e))
|
||||
}
|
||||
console.log(values)
|
||||
}
|
||||
|
||||
async function confirmStateReset() {
|
||||
try {
|
||||
deleteDb("gossip")
|
||||
localStorage.clear();
|
||||
showToast({ title: "Deleted", description: `Deleted all data` })
|
||||
const loadedValues = settingsTemp();
|
||||
|
||||
await actions.setupNodeManager(loadedValues);
|
||||
window.location.reload();
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
showToast(eify(e))
|
||||
}
|
||||
|
||||
setConfirmOpen(false);
|
||||
}
|
||||
|
||||
return <Form onSubmit={handleSubmit} class="flex flex-col gap-4">
|
||||
<ConfirmDialog loading={false} isOpen={confirmOpen()} onConfirm={confirmStateReset} onCancel={() => setConfirmOpen(false)} />
|
||||
<Field name="network">
|
||||
{(field, props) => (
|
||||
// TODO: make a cool select component
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-sm font-semibold uppercase">Network</label>
|
||||
<select {...field} {...props} class="bg-black rounded-xl border border-white px-4 py-2">
|
||||
<option value="mainnet">Mainnet</option>
|
||||
<option value="testnet">Testnet</option>
|
||||
<option value="regtest">Regtest</option>
|
||||
<option value="signet">Signet</option>
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
<Field name="proxy" validate={[url("Should be a url starting with wss://")]}>
|
||||
{(field, props) => (
|
||||
<TextField {...props} value={field.value} error={field.error} label="Websockets Proxy" />
|
||||
)}
|
||||
</Field>
|
||||
<Field name="esplora" validate={[url("That doesn't look like a URL")]}>
|
||||
{(field, props) => (
|
||||
<TextField {...props} value={field.value} error={field.error} label="Esplora" />
|
||||
)}
|
||||
</Field>
|
||||
<Field name="rgs" validate={[url("That doesn't look like a URL")]}>
|
||||
{(field, props) => (
|
||||
<TextField {...props} value={field.value} error={field.error} label="RGS" />
|
||||
)}
|
||||
</Field>
|
||||
<Field name="lsp" validate={[url("That doesn't look like a URL")]}>
|
||||
{(field, props) => (
|
||||
<TextField {...props} value={field.value} error={field.error} label="LSP" />
|
||||
)}
|
||||
</Field>
|
||||
<Button type="submit">Save</Button>
|
||||
</Form>
|
||||
|
||||
}
|
||||
49
src/components/layout/TextField.tsx
Normal file
49
src/components/layout/TextField.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { TextField as KTextField } from '@kobalte/core';
|
||||
import { type JSX, Show, splitProps } from 'solid-js';
|
||||
|
||||
type TextFieldProps = {
|
||||
name: string;
|
||||
type?: 'text' | 'email' | 'tel' | 'password' | 'url' | 'date';
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
value: string | undefined;
|
||||
error: string;
|
||||
required?: boolean;
|
||||
multiline?: boolean;
|
||||
ref: (element: HTMLInputElement | HTMLTextAreaElement) => void;
|
||||
onInput: JSX.EventHandler<HTMLInputElement | HTMLTextAreaElement, InputEvent>;
|
||||
onChange: JSX.EventHandler<HTMLInputElement | HTMLTextAreaElement, Event>;
|
||||
onBlur: JSX.EventHandler<HTMLInputElement | HTMLTextAreaElement, FocusEvent>;
|
||||
};
|
||||
|
||||
export function TextField(props: TextFieldProps) {
|
||||
const [fieldProps] = splitProps(props, [
|
||||
'placeholder',
|
||||
'ref',
|
||||
'onInput',
|
||||
'onChange',
|
||||
'onBlur',
|
||||
]);
|
||||
return (
|
||||
<KTextField.Root
|
||||
class="flex flex-col gap-2"
|
||||
name={props.name}
|
||||
value={props.value}
|
||||
validationState={props.error ? 'invalid' : 'valid'}
|
||||
isRequired={props.required}
|
||||
>
|
||||
<Show when={props.label}>
|
||||
<KTextField.Label class="text-sm uppercase font-semibold">
|
||||
{props.label}
|
||||
</KTextField.Label>
|
||||
</Show>
|
||||
<Show
|
||||
when={props.multiline}
|
||||
fallback={<KTextField.Input {...fieldProps} type={props.type} class="w-full p-2 rounded-lg bg-white/10" />}
|
||||
>
|
||||
<KTextField.TextArea {...fieldProps} autoResize class="w-full p-2 rounded-lg bg-white/10" />
|
||||
</Show>
|
||||
<KTextField.ErrorMessage>{props.error}</KTextField.ErrorMessage>
|
||||
</KTextField.Root>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user