web


git clone https://radroots.dev/git/web.git
Log | Files | Refs | Submodules | README | LICENSE

+page.svelte (6891B)


      1 <script lang="ts">
      2     import { goto } from "$app/navigation";
      3     import { notif, route } from "$lib/utils/app";
      4     import {
      5         import_app_state_from_file,
      6         validate_import_file,
      7     } from "$lib/utils/backup/import";
      8     import { Fade, Glyph } from "@radroots/apps-lib";
      9     import { LogoCircle, SelectMenu } from "@radroots/apps-lib-pwa";
     10     import type { ExportedAppState } from "@radroots/apps-lib-pwa/types/app";
     11     import { ls } from "$lib/utils/i18n";
     12     import { handle_err } from "@radroots/utils";
     13 
     14     let loading = $state(false);
     15     let current_file: File | null = $state(null);
     16     let current_file_validated: ExportedAppState | undefined =
     17         $state(undefined);
     18 
     19     $effect(() => {
     20         if (current_file) {
     21             (async () => {
     22                 try {
     23                     const validated = await validate_import_file(current_file);
     24                     if (validated) current_file_validated = validated;
     25                     else current_file_validated = undefined;
     26                 } catch {
     27                     current_file_validated = undefined;
     28                 }
     29             })();
     30         }
     31     });
     32 
     33     const handle_back = async (): Promise<void> => {
     34         await route("/setup");
     35     };
     36 
     37     const on_change_file = (event: Event): void => {
     38         const target = event.currentTarget as HTMLInputElement | null;
     39         current_file = target?.files?.[0] ?? null;
     40     };
     41 
     42     const submit = async (): Promise<void> => {
     43         try {
     44             if (!current_file)
     45                 return void notif.alert(
     46                     `${$ls(`error.configuration.import.no_file_chosen`)}`,
     47                 );
     48             loading = true;
     49             const import_result =
     50                 await import_app_state_from_file(current_file);
     51             console.log(`import_result `, import_result);
     52             if ("err" in import_result)
     53                 return void (await notif.alert(import_result.err));
     54             else if (import_result.pass === true)
     55                 return void (await goto(`/?ref=backup_imported`));
     56             await notif.alert(
     57                 import_result.message ||
     58                     `${$ls(`error.configuration.import.failure`)}`,
     59             );
     60         } catch (e) {
     61             handle_err(e, `submit`);
     62         } finally {
     63             loading = false;
     64         }
     65     };
     66 </script>
     67 
     68 <button
     69     class={`z-10 absolute top-8 right-6 flex flex-row justify-center items-center`}
     70 >
     71     <SelectMenu
     72         basis={{
     73             layer: 0,
     74             options: [
     75                 {
     76                     entries: [
     77                         {
     78                             value: "",
     79                             label: `${$ls(`common.choose_options`)}`,
     80                             disabled: true,
     81                         },
     82                         {
     83                             value: "back",
     84                             label: `${$ls(`common.go_back`)}`,
     85                         },
     86                     ],
     87                 },
     88             ],
     89             callback: async ({ value }) => {
     90                 if (value === "back") return void (await handle_back());
     91             },
     92         }}
     93     >
     94         <Glyph
     95             basis={{
     96                 classes: `text-base text-ly0-gl group-active:text-ly0-gl-a`,
     97                 key: "gear",
     98             }}
     99         />
    100     </SelectMenu>
    101 </button>
    102 
    103 <div class={`flex flex-col h-screen w-full px-4 justify-center items-start`}>
    104     <div class={`flex flex-col w-full gap-4 justify-center items-start `}>
    105         <LogoCircle />
    106         <div
    107             class={`flex flex-col w-full px-1 gap-1 justify-start items-start`}
    108         >
    109             <p class={`font-sans font-[600] text-lg text-ly0-gl`}>
    110                 {`${$ls(`common.import_app_state`)}`}
    111             </p>
    112             <p class={`font-sans font-[400] text-sm text-ly0-gl/80 max-w-xl`}>
    113                 {`${$ls(`notification.configuration.import_description`)}`}
    114             </p>
    115         </div>
    116         <div class={`flex flex-row w-full justify-center items-center`}>
    117             <input
    118                 type={`file`}
    119                 accept={`application/json,.json`}
    120                 class={`w-full py-2 pl-2 bg-ly0-gl/5 text-ly0-gl text-sm border border-ly0-gl/30 rounded-xl`}
    121                 onchange={on_change_file}
    122             />
    123         </div>
    124         <div class={`flex flex-row h-8 w-full justify-start items-start`}>
    125             {#if current_file}
    126                 <Fade
    127                     basis={{
    128                         classes: `flex-row w-full gap-1 justify-center items-center`,
    129                     }}
    130                 >
    131                     {#if current_file_validated}
    132                         <Glyph
    133                             basis={{
    134                                 classes: `text-base text-lime-600`,
    135                                 key: "check-circle",
    136                                 weight: "fill",
    137                             }}
    138                         />
    139                         <p class={`font-sans font-[500] text-sm text-lime-600`}>
    140                             {`${$ls(
    141                                 `notification.configuration.backup_file_valid`,
    142                                 { backup_version: current_file_validated.backup_version },
    143                             )}`}
    144                         </p>
    145                     {:else}
    146                         <Glyph
    147                             basis={{
    148                                 classes: `text-base text-red-400`,
    149                                 key: "x-circle",
    150                                 weight: "fill",
    151                             }}
    152                         />
    153                         <p class={`font-sans font-[500] text-sm text-red-400`}>
    154                             {`${$ls(`notification.configuration.backup_file_invalid`)}`}
    155                         </p>
    156                     {/if}
    157                 </Fade>
    158             {/if}
    159         </div>
    160         <div class={`flex flex-row h-8 w-full justify-center items-center`}>
    161             {#if current_file && current_file_validated}
    162                 <Fade basis={{ in: { duration: 400 } }}>
    163                     <button
    164                         class={`relative flex flex-row h-8 px-5 justify-center items-center bg-ly1 active:bg-ly1-a rounded-lg text-ly1-gl disabled:opacity-40`}
    165                         disabled={loading}
    166                         onclick={submit}
    167                     >
    168                         {`${$ls(`common.import`)}`}
    169                         {#if loading}
    170                             <Glyph
    171                                 basis={{
    172                                     classes: `absolute -right-6 text-[1px] text-ly0-gl animate-spin-slow`,
    173                                     key: "circle-notch",
    174                                 }}
    175                             />
    176                         {/if}
    177                     </button>
    178                 </Fade>
    179             {/if}
    180         </div>
    181     </div>
    182 </div>