diff --git a/ui/package-lock.json b/ui/package-lock.json
index 519a2cc7..1fad65b1 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -54,6 +54,7 @@
"react-image-size": "^2.0.2",
"react-router-dom": "^6.11.2",
"slugify": "^1.6.0",
+ "usehooks-ts": "^2.9.1",
"zustand": "^3.7.2"
},
"devDependencies": {
@@ -10769,6 +10770,19 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
+ "node_modules/usehooks-ts": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.9.1.tgz",
+ "integrity": "sha512-2FAuSIGHlY+apM9FVlj8/oNhd+1y+Uwv5QNkMQz1oSfdHk4PXo1qoCw9I5M7j0vpH8CSWFJwXbVPeYDjLCx9PA==",
+ "engines": {
+ "node": ">=16.15.0",
+ "npm": ">=8"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"dev": true,
@@ -18525,6 +18539,12 @@
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"requires": {}
},
+ "usehooks-ts": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.9.1.tgz",
+ "integrity": "sha512-2FAuSIGHlY+apM9FVlj8/oNhd+1y+Uwv5QNkMQz1oSfdHk4PXo1qoCw9I5M7j0vpH8CSWFJwXbVPeYDjLCx9PA==",
+ "requires": {}
+ },
"util-deprecate": {
"version": "1.0.2",
"dev": true
diff --git a/ui/package.json b/ui/package.json
index e030eb13..43f1d114 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -61,9 +61,10 @@
"react-dom": "^17.0.2",
"react-error-boundary": "^3.1.3",
"react-hook-form": "^7.38.0",
- "react-router-dom": "^6.11.2",
"react-image-size": "^2.0.2",
+ "react-router-dom": "^6.11.2",
"slugify": "^1.6.0",
+ "usehooks-ts": "^2.9.1",
"zustand": "^3.7.2"
},
"devDependencies": {
diff --git a/ui/src/components/ShipCode.tsx b/ui/src/components/ShipCode.tsx
new file mode 100644
index 00000000..8afd50c6
--- /dev/null
+++ b/ui/src/components/ShipCode.tsx
@@ -0,0 +1,23 @@
+import React, { FunctionComponent, useState } from 'react';
+import useAccessKey from '@/state/code';
+import { useCopy } from '@/logic/utils';
+
+export const ShipCode: FunctionComponent = () => {
+ const { code } = useAccessKey();
+ const [show, setShow] = useState(false);
+
+ const { didCopy, doCopy } = useCopy(code);
+
+ return show ? (
+
+
{code}
+
+
+ ) : (
+
+ );
+};
diff --git a/ui/src/logic/utils.ts b/ui/src/logic/utils.ts
index 865139f8..59f0ec9d 100644
--- a/ui/src/logic/utils.ts
+++ b/ui/src/logic/utils.ts
@@ -10,6 +10,8 @@ import { findLast } from 'lodash';
import { hsla, parseToHsla, parseToRgba } from 'color2k';
import _ from 'lodash';
import { differenceInDays, endOfToday, format } from 'date-fns';
+import { useCopyToClipboard } from 'usehooks-ts';
+import { useCallback, useState } from 'react';
export const useMockData = import.meta.env.MODE === 'mock';
@@ -150,3 +152,28 @@ export async function asyncWithDefault(
return def;
}
}
+
+export function useCopy(copied: string) {
+ const [didCopy, setDidCopy] = useState(false);
+ const [, copy] = useCopyToClipboard();
+
+ const doCopy = useCallback(async () => {
+ let success = false;
+ success = await copy(copied);
+ setDidCopy(success);
+
+ let timeout: NodeJS.Timeout;
+ if (success) {
+ timeout = setTimeout(() => {
+ setDidCopy(false);
+ }, 2000);
+ }
+
+ return () => {
+ setDidCopy(false);
+ clearTimeout(timeout);
+ };
+ }, [copied, copy]);
+
+ return { doCopy, didCopy };
+}
diff --git a/ui/src/preferences/about-system/AboutSystem.tsx b/ui/src/preferences/about-system/AboutSystem.tsx
index 6bb0181d..106cad8d 100644
--- a/ui/src/preferences/about-system/AboutSystem.tsx
+++ b/ui/src/preferences/about-system/AboutSystem.tsx
@@ -14,6 +14,7 @@ import { usePike, useLag } from '../../state/kiln';
import useVereState from '../../state/vere';
import { disableDefault, pluralize } from '@/logic/utils';
import { UpdatePreferences } from './UpdatePreferences';
+import { ShipCode } from '@/components/ShipCode';
function getHash(pike: Pike): string {
const parts = pike.hash.split('.');
@@ -30,9 +31,9 @@ export const AboutSystem = () => {
const lag = useLag();
const vere = useVereState.getState();
- const {isLatest, vereVersion, latestVereVersion, loaded} = vere;
+ const { isLatest, vereVersion, latestVereVersion, loaded } = vere;
- const runtimeUpToDate = (!loaded || isLatest)
+ const runtimeUpToDate = !loaded || isLatest;
return (
<>
@@ -57,7 +58,10 @@ export const AboutSystem = () => {
System update failed because your runtime was out of date.
- Your runtime version is {vereVersion}, the latest runtime version is {latestVereVersion}.
+
+ Your runtime version is {vereVersion}, the latest runtime
+ version is {latestVereVersion}.
+
Update your runtime or contact your hosting provider.
Once your runtime is up to date, click retry below.