@peers-app/peers-ui 0.20.6 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/dist/root-layout/root-layout-host.js +3 -0
  2. package/dist/screens/device-pairing/device-pairing-invite.d.ts +10 -0
  3. package/dist/screens/device-pairing/device-pairing-invite.js +50 -0
  4. package/dist/screens/device-pairing/device-pairing-invite.test.d.ts +1 -0
  5. package/dist/screens/device-pairing/device-pairing-invite.test.js +30 -0
  6. package/dist/screens/device-pairing/device-pairing.d.ts +10 -0
  7. package/dist/screens/device-pairing/device-pairing.js +237 -0
  8. package/dist/screens/device-pairing/device-pairing.test.d.ts +1 -0
  9. package/dist/screens/device-pairing/device-pairing.test.js +88 -0
  10. package/dist/screens/device-pairing/index.d.ts +3 -0
  11. package/dist/screens/device-pairing/index.js +19 -0
  12. package/dist/screens/device-pairing/use-device-pairing-state.d.ts +3 -0
  13. package/dist/screens/device-pairing/use-device-pairing-state.js +31 -0
  14. package/dist/screens/settings/settings-page.js +6 -1
  15. package/dist/screens/setup-user.js +24 -1
  16. package/package.json +3 -3
  17. package/src/root-layout/root-layout-host.tsx +3 -0
  18. package/src/screens/device-pairing/device-pairing-invite.test.ts +50 -0
  19. package/src/screens/device-pairing/device-pairing-invite.ts +55 -0
  20. package/src/screens/device-pairing/device-pairing.test.tsx +100 -0
  21. package/src/screens/device-pairing/device-pairing.tsx +390 -0
  22. package/src/screens/device-pairing/index.ts +3 -0
  23. package/src/screens/device-pairing/use-device-pairing-state.ts +38 -0
  24. package/src/screens/settings/settings-page.tsx +22 -0
  25. package/src/screens/setup-user.tsx +63 -1
@@ -19,6 +19,7 @@ import { Tooltip } from "../../components/tooltip";
19
19
  import * as globals from "../../globals";
20
20
  import { useObservable, useObservableState, usePromise } from "../../hooks";
21
21
  import { LayoutPicker } from "../../root-layout/layout-picker";
22
+ import { SourceDevicePairing } from "../device-pairing";
22
23
  import { ColorModeDropdown } from "./color-mode-dropdown";
23
24
  import { VoiceSettings } from "./voice-settings";
24
25
 
@@ -71,6 +72,7 @@ const UserSettingsTab: React.FC = () => {
71
72
  return (
72
73
  <>
73
74
  <ProfileSection />
75
+ <AddDeviceSection />
74
76
  <LogoutSection />
75
77
  </>
76
78
  );
@@ -250,6 +252,26 @@ const ProfileSection: React.FC = () => {
250
252
  );
251
253
  };
252
254
 
255
+ const AddDeviceSection: React.FC = () => {
256
+ const [open, setOpen] = useState(false);
257
+ return (
258
+ <section className="mt-4 pt-3 border-top">
259
+ <h6>Add another device</h6>
260
+ <p className="small text-muted">
261
+ Create a five-minute invitation, compare the same number on both devices, and approve on
262
+ each one before account access is transferred.
263
+ </p>
264
+ {open ? (
265
+ <SourceDevicePairing onClose={() => setOpen(false)} />
266
+ ) : (
267
+ <button type="button" className="btn btn-outline-primary" onClick={() => setOpen(true)}>
268
+ Add another device
269
+ </button>
270
+ )}
271
+ </section>
272
+ );
273
+ };
274
+
253
275
  const PackagesRootDirectory: React.FC = () => {
254
276
  return (
255
277
  <div className="mt-3">
@@ -7,8 +7,13 @@ import {
7
7
  rpcServerCalls,
8
8
  signMessageWithSecretKey,
9
9
  } from "@peers-app/peers-sdk";
10
- import { useState } from "react";
10
+ import { useEffect, useState } from "react";
11
11
  import { useObservable } from "../hooks";
12
+ import {
13
+ consumePendingDevicePairingInvite,
14
+ DEVICE_PAIRING_INVITE_CAPTURED_EVENT,
15
+ DestinationDevicePairing,
16
+ } from "./device-pairing";
12
17
  import { colorMode } from "./settings/color-mode-dropdown";
13
18
 
14
19
  type SetupStep = "select-user-type" | "complete";
@@ -16,6 +21,10 @@ type SetupStep = "select-user-type" | "complete";
16
21
  export const SetupUser = () => {
17
22
  const [_colorMode] = useObservable(colorMode);
18
23
  const [step, _setStep] = useState<SetupStep>("select-user-type");
24
+ const [pairingInvitation, setPairingInvitation] = useState<string | undefined>(() =>
25
+ consumePendingDevicePairingInvite(),
26
+ );
27
+ const [showPairing, setShowPairing] = useState(() => Boolean(pairingInvitation));
19
28
  const [isExistingUser, setIsExistingUser] = useState<boolean | null>(null);
20
29
  const [userId, setUserId] = useState("");
21
30
  const [secretKey, setSecretKey] = useState("");
@@ -26,6 +35,17 @@ export const SetupUser = () => {
26
35
 
27
36
  const isDark = _colorMode === "dark";
28
37
 
38
+ useEffect(() => {
39
+ const capture = (event: Event) => {
40
+ const invitation = (event as CustomEvent<string>).detail;
41
+ setPairingInvitation(invitation);
42
+ consumePendingDevicePairingInvite();
43
+ setShowPairing(true);
44
+ };
45
+ window.addEventListener(DEVICE_PAIRING_INVITE_CAPTURED_EVENT, capture);
46
+ return () => window.removeEventListener(DEVICE_PAIRING_INVITE_CAPTURED_EVENT, capture);
47
+ }, []);
48
+
29
49
  const handleNewUser = async () => {
30
50
  setError("");
31
51
  setIsValidating(true);
@@ -85,6 +105,35 @@ export const SetupUser = () => {
85
105
  }
86
106
  };
87
107
 
108
+ if (showPairing) {
109
+ return (
110
+ <div
111
+ className="container-fluid d-flex align-items-start justify-content-center"
112
+ style={{ paddingTop: "20px", backgroundColor: isDark ? "#212529" : "#f8f9fa" }}
113
+ >
114
+ <div
115
+ className="card shadow"
116
+ style={{
117
+ maxWidth: "560px",
118
+ width: "100%",
119
+ backgroundColor: isDark ? "#2d3238" : "#ffffff",
120
+ }}
121
+ >
122
+ <div className="card-body p-4 p-md-5">
123
+ <DestinationDevicePairing
124
+ initialInvitation={pairingInvitation}
125
+ onInvitationConsumed={() => setPairingInvitation(undefined)}
126
+ onBack={() => {
127
+ setPairingInvitation(undefined);
128
+ setShowPairing(false);
129
+ }}
130
+ />
131
+ </div>
132
+ </div>
133
+ </div>
134
+ );
135
+ }
136
+
88
137
  // Step 1: Select User Type
89
138
  if (step === "select-user-type" && isExistingUser === null) {
90
139
  return (
@@ -134,6 +183,19 @@ export const SetupUser = () => {
134
183
  </div>
135
184
  </div>
136
185
  </button>
186
+
187
+ <button
188
+ className={`btn btn-lg py-3 ${isDark ? "btn-outline-light" : "btn-outline-primary"}`}
189
+ onClick={() => setShowPairing(true)}
190
+ >
191
+ <div className="d-flex align-items-center justify-content-center">
192
+ <i className="bi bi-phone fs-4 me-2" />
193
+ <div className="text-start">
194
+ <div className="fw-semibold">Use Another Device</div>
195
+ <small className="opacity-75">Sign in with a device already on Peers</small>
196
+ </div>
197
+ </div>
198
+ </button>
137
199
  </div>
138
200
  </div>
139
201
  </div>