add device popup modal

This commit is contained in:
myung03
2024-10-07 15:51:00 -07:00
parent a08c890f86
commit eef0a59293
6 changed files with 115 additions and 16 deletions

View File

@@ -3,6 +3,7 @@ import clsx from 'clsx';
import { useClientContext } from '@sd/client';
import { dialogManager, Dropdown, DropdownMenu } from '@sd/ui';
import JoinDialog from '~/app/$libraryId/settings/node/libraries/JoinDialog';
import RequestAddDialog from '~/components/RequestAddDialog';
import { useLocale } from '~/hooks';
import CreateDialog from '../../../settings/node/libraries/CreateDialog';

View File

@@ -1,15 +1,7 @@
import { useQueryClient } from '@tanstack/react-query';
import { useNavigate } from 'react-router';
import {
LibraryConfigWrapped,
useBridgeMutation,
useBridgeQuery,
useClientContext,
useLibraryContext,
usePlausibleEvent,
useZodForm
} from '@sd/client';
import { Button, Dialog, Select, SelectOption, toast, useDialog, UseDialogProps, z } from '@sd/ui';
import { LibraryConfigWrapped, useBridgeMutation, useBridgeQuery, useZodForm } from '@sd/client';
import { Dialog, Loader, Select, SelectOption, toast, useDialog, UseDialogProps, z } from '@sd/ui';
import { useLocale } from '~/hooks';
import { usePlatform } from '~/util/Platform';
@@ -67,7 +59,12 @@ export default (props: UseDialogProps & { librariesCtx: LibraryConfigWrapped[] |
ctaLabel={form.formState.isSubmitting ? t('joining') : t('join')}
>
<div className="mt-5 space-y-4">
{cloudLibraries.isLoading && <span>{t('loading')}...</span>}
{cloudLibraries.isLoading && (
<div className="mt-4 flex flex-col items-center justify-center gap-2">
<Loader className="size-5"></Loader>
<span className="text-xs text-ink-faint">{t('loading')}...</span>
</div>
)}
{cloudLibraries.data && (
<Select
value={form.watch('libraryId')}

View File

@@ -0,0 +1,89 @@
import { ArrowRight } from '@phosphor-icons/react';
import { useQueryClient } from '@tanstack/react-query';
import { useNavigate } from 'react-router';
import { HardwareModel, useBridgeMutation, useZodForm } from '@sd/client';
import { Dialog, toast, useDialog, UseDialogProps, z } from '@sd/ui';
import { Icon } from '~/components';
import { useLocale } from '~/hooks';
import { hardwareModelToIcon } from '~/util/hardware';
import { usePlatform } from '~/util/Platform';
export default (props: UseDialogProps) => {
// PROPS = device_name, device_model, library_name
// you will probably have to change the props to accept the library id and device id to pair them properly. Omitted for now as
// unsure what the data will look like when the backend is populated
const joinLibrary = useBridgeMutation(['cloud.library.join']);
const { t } = useLocale();
const navigate = useNavigate();
const platform = usePlatform();
const queryClient = useQueryClient();
const form = useZodForm({ defaultValues: { libraryId: 'select_library' } });
// adapted from another dialog - we can change the form submit/remove form if needed but didn't want to
// unnecessarily remove code
const onSubmit = form.handleSubmit(async (data) => {
try {
const library = await joinLibrary.mutateAsync(data.libraryId);
queryClient.setQueryData(['library.list'], (libraries: any) => {
// The invalidation system beat us to it
if ((libraries || []).find((l: any) => l.uuid === library.uuid)) return libraries;
return [...(libraries || []), library];
});
if (platform.refreshMenuBar) platform.refreshMenuBar();
navigate(`/${library.uuid}`, { replace: true });
} catch (e: any) {
console.error(e);
toast.error(e);
}
});
return (
<Dialog
form={form}
onSubmit={onSubmit}
dialog={useDialog(props)}
submitDisabled={!form.formState.isValid}
title={t('request_add_device')}
cancelLabel={t('cancel')}
cancelDanger={true}
cancelBtn={true}
onCancelled={false}
description={t('request_add_device_description')}
ignoreClickOutside={true}
ctaLabel={form.formState.isSubmitting ? t('accepting') : t('accept')}
>
{/* device */}
<div className="my-6 flex items-center justify-center gap-10">
<div className="flex flex-col items-center justify-center gap-2">
<Icon
// once backend endpoint is populated need to check if this is working correctly i.e fetching correct icons for devices
name={hardwareModelToIcon(props.device_model as HardwareModel)}
alt="Device icon"
size={48}
className="mr-2"
/>
<p className="text-sm text-ink-dull">{props.device_name}</p>
</div>
<ArrowRight color="#ABACBA" size={18}></ArrowRight>
{/* library */}
<div className="flex flex-col items-center justify-center gap-2">
<Icon
// once backend endpoint is populated need to check if this is working correctly i.e fetching correct icons for devices
name={'Book'}
alt="Device icon"
size={48}
className="mr-2"
/>
<p className="text-sm text-ink-dull">{props.library_name}</p>
</div>
</div>
</Dialog>
);
};

View File

@@ -12,7 +12,8 @@ import {
useInvalidateQuery,
useLoadBackendFeatureFlags
} from '@sd/client';
import { toast, TooltipProvider } from '@sd/ui';
import { dialogManager, toast, TooltipProvider } from '@sd/ui';
import RequestAddDialog from '~/components/RequestAddDialog';
import { createRoutes } from './app';
import { SpacedropProvider } from './app/$libraryId/Spacedrop';
@@ -92,10 +93,16 @@ export function SpacedriveInterfaceRoot({ children }: PropsWithChildren) {
console.log('Received cloud service notification', d);
switch (d.kind) {
case 'ReceivedJoinSyncGroupRequest':
// TODO: Show modal to accept or reject
dialogManager.create((dp) => (
<RequestAddDialog
device_model={'Macbook Pro'}
device_name={"Arnab's Macbook"}
library_name={"Arnab's Library"}
{...dp}
/>
));
break;
default:
// TODO: Show notification/toast for other kinds
toast({ title: 'Cloud Service Notification', body: d.kind }, { type: 'info' });
break;
}

View File

@@ -4,6 +4,7 @@
"about_vision_title": "Vision",
"accept": "Accept",
"accept_files": "Accept files",
"accepting": "Accepting...",
"accessed": "Accessed",
"account": "Account",
"actions": "Actions",
@@ -617,6 +618,8 @@
"rename": "Rename",
"rename_object": "Rename object",
"replica": "Replica",
"request_add_device": "Library Join Request",
"request_add_device_description": "A device is requesting to join one of your libraries. Please review the device and the library it is requesting to join below.",
"rescan": "Rescan",
"rescan_directory": "Rescan Directory",
"rescan_location": "Rescan Location",

View File

@@ -124,6 +124,7 @@ export interface DialogProps<S extends FieldValues>
onSubmitSecond?: ReturnType<UseFormHandleSubmit<S>>;
children?: ReactNode;
ctaDanger?: boolean;
cancelDanger?: boolean;
closeLabel?: string;
cancelLabel?: string;
cancelBtn?: boolean;
@@ -167,8 +168,9 @@ export function Dialog<S extends FieldValues>({
<RDialog.Close asChild>
<Button
size="sm"
variant="gray"
variant={props.cancelDanger ? 'colored' : 'gray'}
onClick={typeof onCancelled === 'function' ? onCancelled : undefined}
className={clsx(props.cancelDanger && 'border-red-500 bg-red-500')}
>
{props.cancelLabel || 'Cancel'}
</Button>
@@ -180,7 +182,7 @@ export function Dialog<S extends FieldValues>({
<Button
disabled={props.loading}
size="sm"
variant="gray"
variant={'gray'}
onClick={typeof onCancelled === 'function' ? onCancelled : undefined}
>
{props.closeLabel || 'Close'}