Skip to content

Commit

Permalink
refactor: better error feedback on copy to clipboard
Browse files Browse the repository at this point in the history
  • Loading branch information
matyson committed Mar 26, 2024
1 parent fa0a3f1 commit 00dc15c
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 34 deletions.
41 changes: 27 additions & 14 deletions apps/pianno/components/toolbar/save.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
Expand Down Expand Up @@ -199,6 +198,8 @@ const formSchema = z.object({
geometry: z.string(),
});

type CopyState = 'copied' | 'error' | 'idle';

const SaveForm = () => {
const viewport = useStoreViewport();
const { points } = useAnnotationPoints();
Expand All @@ -211,8 +212,8 @@ const SaveForm = () => {
})),
[points],
);
const [isCopied, setIsCopied] = useState(false);
const [_, copy] = useCopyToClipboard();
const [isCopied, setIsCopied] = useState<CopyState>('idle');
const [copy] = useCopyToClipboard();

const form = useForm<z.infer<typeof formSchema>>({
defaultValues: {
Expand Down Expand Up @@ -243,22 +244,26 @@ const SaveForm = () => {
toast.success('Annotations saved successfully!');
})
.catch((err) => {
toast.error('Annotations could not be saved!');
toast.error(err.message || 'Annotations could not be saved!');
});
};

const onCopy = (data: z.infer<typeof formSchema>) => {
const metadata = formatMetadata(data);
copy(JSON.stringify(metadata))
copy(JSON.stringify(metadata, null, 2))
.then(() => {
setIsCopied(true);
setIsCopied('copied');
toast.success('Annotations copied to clipboard!');
setTimeout(() => {
setIsCopied(false);
}, 1000);
setIsCopied('idle');
}, 2000);
})
.catch((err) => {
toast.error('Annotations could not be copied!');
setIsCopied('error');
toast.error(err.message || 'Annotations could not be copied!');
setTimeout(() => {
setIsCopied('idle');
}, 2000);
});
};

Expand Down Expand Up @@ -480,14 +485,22 @@ const SaveForm = () => {
size="icon"
variant="outline"
>
{isCopied ? (
<CheckIcon className="h-4 w-4" />
) : (
<CopyIcon className="h-4 w-4" />
)}
<CopyButtonIcon isCopied={isCopied} />
</Button>
</div>
</form>
</Form>
);
};

const CopyButtonIcon = ({ isCopied }: { isCopied: CopyState }) => {
if (isCopied === 'copied') {
return <CheckIcon className="h-4 w-4" />;
}
if (isCopied === 'error') {
return <BanIcon className="h-4 w-4" />;
}
if (isCopied === 'idle') {
return <CopyIcon className="h-4 w-4" />;
}
};
59 changes: 39 additions & 20 deletions apps/pianno/hooks/use-copy-to-clipboard.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,47 @@
import { useState } from 'react'
import { useState } from 'react';

type CopiedValue = null | string
type CopyFn = (text: string) => Promise<boolean> // Return success
type CopyToClipboard = {
data: string;
isError: boolean;
message?: string;
};

export function useCopyToClipboard(): [CopiedValue, CopyFn] {
const [copiedText, setCopiedText] = useState<CopiedValue>(null)
export const useCopyToClipboard = (): [
(text: string) => Promise<void>,
CopyToClipboard,
] => {
const [copyResult, setCopyResult] = useState<CopyToClipboard>({
data: '',
isError: false,
});

const copy: CopyFn = async text => {
if (!navigator?.clipboard) {
console.warn('Clipboard not supported')
return false
const copyToClipboard = async (text: string) => {
if (!navigator.clipboard) {
setCopyResult({
data: text,
isError: true,
message: 'Clipboard API not available',
});
throw new Error('Clipboard API not available');
}

// Try to save to clipboard then save it in the state if worked
try {
await navigator.clipboard.writeText(text)
setCopiedText(text)
return true
} catch (error) {
console.warn('Copy failed', error)
setCopiedText(null)
return false
await navigator.clipboard.writeText(text);
setCopyResult({
data: text,
isError: false,
message: 'Copied to clipboard',
});
} catch (err) {
setCopyResult({
data: text,
isError: true,
message:
err instanceof Error ? err.message : 'Failed to copy to clipboard',
});
throw err;
}
}
};

return [copiedText, copy]
}
return [copyToClipboard, copyResult];
};

0 comments on commit 00dc15c

Please sign in to comment.