Skip to content

Commit 443d06b

Browse files
author
Guru
committed
feat: badge component and passkey
1 parent 9390e9d commit 443d06b

File tree

2 files changed

+226
-16
lines changed

2 files changed

+226
-16
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import * as React from "react";
2+
import { cn } from "./Card";
3+
4+
interface BadgeProps {
5+
size?: "small" | "large";
6+
variant?: "default" | "primary" | "success" | "danger" | "warning" | "info";
7+
pill?: boolean;
8+
border?: boolean;
9+
clearIcon?: boolean;
10+
id?: string;
11+
classes?: {
12+
container?: string;
13+
clearIcon?: string;
14+
};
15+
component?: React.ElementType;
16+
onClear?: () => void;
17+
children?: React.ReactNode;
18+
}
19+
20+
const Badge: React.FC<BadgeProps> = ({
21+
size = "small",
22+
variant = "default",
23+
pill = false,
24+
border = false,
25+
clearIcon = false,
26+
id = "",
27+
classes = {},
28+
component: Component = "span",
29+
onClear,
30+
children,
31+
}) => {
32+
const sizeClasses = size === "large" ? "py-0.5 px-3 text-xs leading-4 h-6" : "py-0.5 px-2.5 text-xs leading-4 h-5";
33+
const variantClasses = {
34+
default: "bg-app-gray-100 text-app-gray-900 dark:bg-app-gray-700 dark:text-app-gray-300",
35+
primary: "bg-app-primary-100 text-app-primary-800 dark:bg-app-primary-900 dark:text-app-primary-400",
36+
success: "bg-app-green-100 text-app-green-800 dark:bg-app-gray-700 dark:text-app-green-400",
37+
danger: "bg-app-red-100 text-app-red-800 dark:bg-app-gray-700 dark:text-app-red-400",
38+
warning: "bg-app-yellow-100 text-app-yellow-800 dark:bg-app-gray-700 dark:text-app-yellow-300",
39+
info: "bg-app-primary-100 text-app-primary-800 dark:bg-app-primary-900 dark:text-app-primary-400",
40+
}[variant];
41+
const borderClasses = border ? `border ${variantClasses.split(" ")[1]}-border` : "";
42+
43+
return (
44+
<Component
45+
id={id}
46+
className={cn(
47+
"inline-flex items-center font-medium",
48+
sizeClasses,
49+
variantClasses,
50+
pill ? "rounded-full" : "rounded-md",
51+
borderClasses,
52+
classes.container
53+
)}
54+
role="status"
55+
>
56+
{children}
57+
{clearIcon && (
58+
<button
59+
type="button"
60+
className={cn(
61+
"inline-flex items-center p-0.5 ml-2 text-sm bg-app-transparent rounded-sm",
62+
classes.clearIcon
63+
)}
64+
data-dismiss-target={`#${id || `badge-dismiss-${variant}`}`}
65+
aria-label="Remove"
66+
onClick={onClear}
67+
>
68+
<span className="sr-only">Remove badge</span>
69+
<svg
70+
className="w-[15px]"
71+
fill="none"
72+
stroke="currentColor"
73+
viewBox="0 0 24 24"
74+
xmlns="http://www.w3.org/2000/svg"
75+
>
76+
<path
77+
strokeLinecap="round"
78+
strokeLinejoin="round"
79+
strokeWidth={2}
80+
d="M6 18L18 6M6 6l12 12"
81+
/>
82+
</svg>
83+
</button>
84+
)}
85+
</Component>
86+
);
87+
};
88+
89+
export default Badge;

demo/redirect-flow-example/src/components/PasskeyCard.tsx

Lines changed: 137 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@ import * as React from "react";
22
import { Button } from "./Button";
33
import { Card } from "./Card";
44
import { useCoreKit } from "../composibles/useCoreKit";
5-
import { shouldSupportPasskey } from "../App";
65
import { HiOutlineMinusCircle } from "react-icons/hi";
76
import { HiOutlineKey } from "react-icons/hi";
7+
import Badge from "./Badge";
8+
9+
interface Passkey {
10+
verifier_id: string;
11+
verifier: string;
12+
passkey_pub_key: string;
13+
label: string;
14+
}
815

916
const PasskeysCard: React.FC = () => {
1017
const { passkeyPlugin, coreKitInstance } = useCoreKit();
1118
const [hasPasskeys, setHasPasskeys] = React.useState(false);
1219
const [isLoading, setIsLoading] = React.useState(false);
13-
interface Passkey {
14-
verifier_id: string;
15-
verifier: string;
16-
passkey_pub_key: string;
17-
label: string;
18-
}
19-
2020
const [passkeys, setPasskeys] = React.useState<Passkey[]>([]);
2121

2222
React.useEffect(() => {
@@ -43,11 +43,11 @@ const PasskeysCard: React.FC = () => {
4343
if (!passkeyPlugin) {
4444
throw new Error("passkeyPlugin is not set");
4545
}
46-
const result = shouldSupportPasskey();
47-
if (!result.isBrowserSupported) {
48-
console.log("Browser not supported");
49-
throw new Error("Browser not supported");
50-
}
46+
// const result = shouldSupportPasskey();
47+
// if (!result.isBrowserSupported) {
48+
// console.log("Browser not supported");
49+
// throw new Error("Browser not supported");
50+
// }
5151
await passkeyPlugin.registerPasskey();
5252
} catch (error) {
5353
console.error(error);
@@ -77,6 +77,7 @@ const PasskeysCard: React.FC = () => {
7777
<div className="mb-4">
7878
<div className="flex justify-between items-center mb-1">
7979
<h3 className="font-semibold text-app-gray-900 dark:text-app-white">Passkeys</h3>
80+
<Badge variant="default">Coming soon</Badge>
8081
</div>
8182
<p className="text-xs text-app-gray-500 dark:text-app-gray-400">Link a passkey to your account</p>
8283
</div>
@@ -85,8 +86,7 @@ const PasskeysCard: React.FC = () => {
8586
size="sm"
8687
className="gap-2 w-full !border-app-gray-300 !text-app-gray-800 dark:!text-app-white disabled:!text-app-gray-400"
8788
variant="secondary"
88-
onClick={registerPasskey}
89-
loading={isLoading}
89+
disabled
9090
>
9191
Register a Passkey
9292
</Button>
@@ -107,7 +107,6 @@ const PasskeysCard: React.FC = () => {
107107
<div className="ml-auto">
108108
<Button loading={isLoading} rounded variant="text" onClick={() => deletePasskey(passkey.passkey_pub_key)}>
109109
<HiOutlineMinusCircle className="text-app-gray-900 dark:text-app-white w-5 h-5"/>
110-
<></>
111110
</Button>
112111
</div>
113112
</div>
@@ -119,3 +118,125 @@ const PasskeysCard: React.FC = () => {
119118
};
120119

121120
export { PasskeysCard };
121+
122+
// import * as React from "react";
123+
// import { Button } from "./Button";
124+
// import { Card } from "./Card";
125+
// import { useCoreKit } from "../composibles/useCoreKit";
126+
// import { shouldSupportPasskey } from "../App";
127+
// import { HiOutlineMinusCircle } from "react-icons/hi";
128+
// import { HiOutlineKey } from "react-icons/hi";
129+
130+
// const PasskeysCard: React.FC = () => {
131+
// const { passkeyPlugin, coreKitInstance } = useCoreKit();
132+
// const [hasPasskeys, setHasPasskeys] = React.useState(false);
133+
// const [isLoading, setIsLoading] = React.useState(false);
134+
// interface Passkey {
135+
// verifier_id: string;
136+
// verifier: string;
137+
// passkey_pub_key: string;
138+
// label: string;
139+
// }
140+
141+
// const [passkeys, setPasskeys] = React.useState<Passkey[]>([]);
142+
143+
// React.useEffect(() => {
144+
// listPasskeys();
145+
// }, []);
146+
147+
// React.useEffect(() => {
148+
// if (passkeys.length > 0) {
149+
// setHasPasskeys(true);
150+
// }
151+
// }, [passkeys]);
152+
153+
// const deletePasskey = (id: string) => {
154+
// console.log("delete passkey", id);
155+
// passkeyPlugin?.unRegisterPasskey({ credentialPubKey: id, verifier: "web3auth" } as any);
156+
// };
157+
158+
// const registerPasskey = async () => {
159+
// setIsLoading(true);
160+
// try {
161+
// if (!coreKitInstance) {
162+
// throw new Error("coreKitInstance is not set");
163+
// }
164+
// if (!passkeyPlugin) {
165+
// throw new Error("passkeyPlugin is not set");
166+
// }
167+
// const result = shouldSupportPasskey();
168+
// if (!result.isBrowserSupported) {
169+
// console.log("Browser not supported");
170+
// throw new Error("Browser not supported");
171+
// }
172+
// await passkeyPlugin.registerPasskey();
173+
// } catch (error) {
174+
// console.error(error);
175+
// } finally {
176+
// setIsLoading(false);
177+
// }
178+
// };
179+
180+
// const listPasskeys = async () => {
181+
// try {
182+
// if (!coreKitInstance) {
183+
// throw new Error("coreKitInstance is not set");
184+
// }
185+
// if (!passkeyPlugin) {
186+
// throw new Error("passkeyPlugin is not set");
187+
// }
188+
// const passkeys = await passkeyPlugin.listPasskeys();
189+
// console.log({ passkeyPlugin, passkeys });
190+
// setPasskeys(passkeys);
191+
// } catch (error) {
192+
// console.error(error);
193+
// }
194+
// };
195+
196+
// return (
197+
// <Card className="px-8 py-6 w-full !rounded-2xl !shadow-modal !border-0 dark:!border-app-gray-800 dark:!shadow-dark">
198+
// <div className="mb-4">
199+
// <div className="flex justify-between items-center mb-1">
200+
// <h3 className="font-semibold text-app-gray-900 dark:text-app-white">Passkeys</h3>
201+
// </div>
202+
// <p className="text-xs text-app-gray-500 dark:text-app-gray-400">Link a passkey to your account</p>
203+
// </div>
204+
205+
// <Button
206+
// size="sm"
207+
// className="gap-2 w-full !border-app-gray-300 !text-app-gray-800 dark:!text-app-white disabled:!text-app-gray-400"
208+
// variant="secondary"
209+
// onClick={registerPasskey}
210+
// loading={isLoading}
211+
// >
212+
// Register a Passkey
213+
// </Button>
214+
215+
// {hasPasskeys && <div className="mt-4 mb-0 border-t border-app-gray-200 dark:border-app-gray-500"></div>}
216+
217+
// {hasPasskeys && (
218+
// <div className="divide-y divide-app-gray-200 dark:divide-app-gray-500">
219+
// {passkeys.map((passkey) => (
220+
// <div key={passkey.label} className="flex items-center py-4">
221+
// <div className="mr-2">
222+
// <HiOutlineKey name="key-icon" className="text-app-gray-900 dark:text-app-white w-5 h-5" />
223+
// </div>
224+
// <div>
225+
// <h4 className="text-sm font-semibold text-app-gray-900 dark:text-app-white">{passkey.label}</h4>
226+
// <p className="text-xs text-app-gray-400">{passkey.verifier_id}</p>
227+
// </div>
228+
// <div className="ml-auto">
229+
// <Button loading={isLoading} rounded variant="text" onClick={() => deletePasskey(passkey.passkey_pub_key)}>
230+
// <HiOutlineMinusCircle className="text-app-gray-900 dark:text-app-white w-5 h-5"/>
231+
// <></>
232+
// </Button>
233+
// </div>
234+
// </div>
235+
// ))}
236+
// </div>
237+
// )}
238+
// </Card>
239+
// );
240+
// };
241+
242+
// export { PasskeysCard };

0 commit comments

Comments
 (0)