From 0cd3946c17586b7f2c6f6653ef21c44cedd98453 Mon Sep 17 00:00:00 2001 From: Akash Shaw Date: Fri, 29 Mar 2024 17:45:24 +0530 Subject: [PATCH 01/10] fix: default account name state management --- .../account/components/account-switcher.tsx | 2 +- .../create/components/account-create-form.tsx | 36 ++++------ apps/web/app/account/page.tsx | 14 +++- backend/backend-common/src/db/friendship.ts | 2 + backend/hasura/docker-compose.yml | 2 +- .../default/tables/public_friendship.yaml | 4 +- .../1711640463865_drop_schema_check/down.sql | 3 + .../1711640463865_drop_schema_check/up.sql | 1 + backend/zeus/src/codegen/types.ts | 36 ++++------ backend/zeus/src/zeus/const.ts | 16 ++--- backend/zeus/src/zeus/index.ts | 70 ++++++++++--------- packages/recoil/src/atoms/account.tsx | 29 +++++++- 12 files changed, 120 insertions(+), 95 deletions(-) create mode 100644 backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/down.sql create mode 100644 backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/up.sql diff --git a/apps/web/app/account/components/account-switcher.tsx b/apps/web/app/account/components/account-switcher.tsx index 2daea8c3..3368597b 100644 --- a/apps/web/app/account/components/account-switcher.tsx +++ b/apps/web/app/account/components/account-switcher.tsx @@ -49,7 +49,7 @@ export function AccountSwitcher({ - {accounts.map((account) => ( + {accounts.map((account) => account && (
diff --git a/apps/web/app/account/create/components/account-create-form.tsx b/apps/web/app/account/create/components/account-create-form.tsx index 319c37e7..207b8a82 100644 --- a/apps/web/app/account/create/components/account-create-form.tsx +++ b/apps/web/app/account/create/components/account-create-form.tsx @@ -3,13 +3,11 @@ import * as React from "react"; import { cn } from "@/lib/utils"; -import { Icons } from "@/components/ui/icons"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Form, FormControl, - FormDescription, FormField, FormItem, FormLabel, @@ -18,7 +16,7 @@ import { import { useSession } from "next-auth/react"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; -import { date, z } from "zod"; +import { z } from "zod"; import { AccountCreateQuery, AccountType, @@ -31,7 +29,6 @@ import { loadingAtom } from "@paybox/recoil"; import { RocketIcon } from "@radix-ui/react-icons"; import { toast } from "sonner"; -import { Label } from "@/components/ui/label"; import { Card, @@ -41,20 +38,12 @@ import { CardHeader, CardTitle, } from "@/components/ui/card" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@/components/ui/accordion" -import { Link } from "lucide-react"; import { useRouter } from "next/navigation"; import { AvatarUpload } from "./avatar-upload"; import { accountsAtom, defaultAccountNumberAtom } from "@paybox/recoil"; @@ -76,9 +65,6 @@ export function AccountCreateForm({ const [defaultNumber, setDefaultAccountNumber] = useRecoilState(defaultAccountNumberAtom); const setAccounts = useSetRecoilState(accountsAtom); - React.useEffect(() => { - setDefaultAccountNumber(defaultAccountNumber); - }, [defaultAccountNumber]) const form = useForm>({ resolver: zodResolver(AccountCreateQuery), @@ -88,6 +74,15 @@ export function AccountCreateForm({ }, }); + React.useEffect(() => { + setDefaultAccountNumber(defaultAccountNumber); + }, [defaultAccountNumber]); + + React.useEffect(() => { + form.setValue("name", `Account ${defaultNumber}`); + }, [defaultNumber]); + + async function onSubmit(values: z.infer) { const call = async () => { try { @@ -118,12 +113,6 @@ export function AccountCreateForm({ "Authorization": `Bearer ${jwt}` }, }).then(res => res.json()); - setAccounts((oldAccounts) => { - return [...oldAccounts, response.account] - }); - setDefaultAccountNumber((oldNumber) => { - return oldNumber + 1; - }); return { account: response.account, status: response.status, msg: response.msg } } catch (error) { throw new Error("Error creating Account"); @@ -135,7 +124,10 @@ export function AccountCreateForm({ if (status == responseStatus.Error) { return toast.error(msg) } - //TODO: set the account to the atom + setAccounts((oldAccounts) => { + return [...oldAccounts, account] + }); + setDefaultAccountNumber((oldNumber) => oldNumber + 1); return `Account '${account.name}' Created Successfully` }, error({ status, msg }: { status: responseStatus, msg: string }) { diff --git a/apps/web/app/account/page.tsx b/apps/web/app/account/page.tsx index 02d80fe1..320d9c18 100644 --- a/apps/web/app/account/page.tsx +++ b/apps/web/app/account/page.tsx @@ -1,4 +1,12 @@ -export default function Page({ params }: { params: { id: string } }) { +import { getServerSession } from "next-auth" +import { authOptions } from "../api/auth/[...nextauth]/util" + +export default async function Page({ params, children }: { params: { id: string }, children: React.ReactNode }) { + const session = await getServerSession(authOptions); console.log(params) - return
My Post: {params.id}
-} \ No newline at end of file + return ( +
+ {children} +
+ ); +} diff --git a/backend/backend-common/src/db/friendship.ts b/backend/backend-common/src/db/friendship.ts index ab82005c..79d0cf83 100644 --- a/backend/backend-common/src/db/friendship.ts +++ b/backend/backend-common/src/db/friendship.ts @@ -182,6 +182,7 @@ export const acceptFriendship = async ( return { status: dbResStatus.Ok, friendshipStatus: response.update_friendship?.returning[0].status as FriendshipStatus, + //@ts-ignore to: response.update_friendship?.returning[0].client1.id === clientId ? response.update_friendship?.returning[0].client2.username as string : response.update_friendship?.returning[0].client1.username as string } } @@ -236,6 +237,7 @@ export const putFriendshipStatus = async ( return { status: dbResStatus.Ok, friendshipStatus: response.update_friendship?.returning[0].status as FriendshipStatus, + //@ts-ignore to: response.update_friendship?.returning[0].client1.id === clientId ? response.update_friendship?.returning[0].client2.username as string : response.update_friendship?.returning[0].client1.username as string } } diff --git a/backend/hasura/docker-compose.yml b/backend/hasura/docker-compose.yml index 2667cc46..e256c4be 100644 --- a/backend/hasura/docker-compose.yml +++ b/backend/hasura/docker-compose.yml @@ -29,7 +29,7 @@ services: timeout: 5s hasura: - image: hasura/graphql-engine:v2.38.0 + image: hasura/graphql-engine:v2.18.0.cli-migrations-v3 ports: - 8112:8080 depends_on: diff --git a/backend/hasura/hasura/metadata/databases/default/tables/public_friendship.yaml b/backend/hasura/hasura/metadata/databases/default/tables/public_friendship.yaml index 1800f541..4f16bcd5 100644 --- a/backend/hasura/hasura/metadata/databases/default/tables/public_friendship.yaml +++ b/backend/hasura/hasura/metadata/databases/default/tables/public_friendship.yaml @@ -12,10 +12,10 @@ configuration: updated_at: updatedAt custom_root_fields: {} object_relationships: - - name: client1 + - name: client using: foreign_key_constraint_on: clientId1 - - name: client2 + - name: clientByClientid2 using: foreign_key_constraint_on: clientId2 array_relationships: diff --git a/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/down.sql b/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/down.sql new file mode 100644 index 00000000..9a1299a4 --- /dev/null +++ b/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/down.sql @@ -0,0 +1,3 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- drop schema "check" cascade; diff --git a/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/up.sql b/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/up.sql new file mode 100644 index 00000000..2a17fc26 --- /dev/null +++ b/backend/hasura/hasura/migrations/default/1711640463865_drop_schema_check/up.sql @@ -0,0 +1 @@ +drop schema "check" cascade; diff --git a/backend/zeus/src/codegen/types.ts b/backend/zeus/src/codegen/types.ts index fe55ac0d..34458cb8 100644 --- a/backend/zeus/src/codegen/types.ts +++ b/backend/zeus/src/codegen/types.ts @@ -2082,9 +2082,9 @@ export type Friendship = { /** An aggregate relationship */ chats_aggregate: Chat_Aggregate; /** An object relationship */ - client1: Client; + client: Client; /** An object relationship */ - client2: Client; + clientByClientid2: Client; clientId1: Scalars['uuid']['output']; clientId2: Scalars['uuid']['output']; createdAt: Scalars['timestamptz']['output']; @@ -2167,8 +2167,8 @@ export type Friendship_Bool_Exp = { _or?: InputMaybe>; chats?: InputMaybe; chats_aggregate?: InputMaybe; - client1?: InputMaybe; - client2?: InputMaybe; + client?: InputMaybe; + clientByClientid2?: InputMaybe; clientId1?: InputMaybe; clientId2?: InputMaybe; createdAt?: InputMaybe; @@ -2186,8 +2186,8 @@ export enum Friendship_Constraint { /** input type for inserting data into table "friendship" */ export type Friendship_Insert_Input = { chats?: InputMaybe; - client1?: InputMaybe; - client2?: InputMaybe; + client?: InputMaybe; + clientByClientid2?: InputMaybe; clientId1?: InputMaybe; clientId2?: InputMaybe; createdAt?: InputMaybe; @@ -2264,8 +2264,8 @@ export type Friendship_On_Conflict = { /** Ordering options when selecting data from "friendship". */ export type Friendship_Order_By = { chats_aggregate?: InputMaybe; - client1?: InputMaybe; - client2?: InputMaybe; + client?: InputMaybe; + clientByClientid2?: InputMaybe; clientId1?: InputMaybe; clientId2?: InputMaybe; createdAt?: InputMaybe; @@ -3362,7 +3362,6 @@ export type Notification_Subscription = { id: Scalars['uuid']['output']; p256dh: Scalars['String']['output']; updatedAt: Scalars['timestamptz']['output']; - uuid: Scalars['uuid']['output']; }; /** aggregated selection of "notification_subscription" */ @@ -3425,11 +3424,12 @@ export type Notification_Subscription_Bool_Exp = { id?: InputMaybe; p256dh?: InputMaybe; updatedAt?: InputMaybe; - uuid?: InputMaybe; }; /** unique or primary key constraints on table "notification_subscription" */ export enum Notification_Subscription_Constraint { + /** unique or primary key constraint on columns "endpoint" */ + NotificationSubscriptionEndpointKey = 'notification_subscription_endpoint_key', /** unique or primary key constraint on columns "id" */ NotificationSubscriptionPkey = 'notification_subscription_pkey' } @@ -3444,7 +3444,6 @@ export type Notification_Subscription_Insert_Input = { id?: InputMaybe; p256dh?: InputMaybe; updatedAt?: InputMaybe; - uuid?: InputMaybe; }; /** aggregate max on columns */ @@ -3457,7 +3456,6 @@ export type Notification_Subscription_Max_Fields = { id?: Maybe; p256dh?: Maybe; updatedAt?: Maybe; - uuid?: Maybe; }; /** order by max() on columns of table "notification_subscription" */ @@ -3469,7 +3467,6 @@ export type Notification_Subscription_Max_Order_By = { id?: InputMaybe; p256dh?: InputMaybe; updatedAt?: InputMaybe; - uuid?: InputMaybe; }; /** aggregate min on columns */ @@ -3482,7 +3479,6 @@ export type Notification_Subscription_Min_Fields = { id?: Maybe; p256dh?: Maybe; updatedAt?: Maybe; - uuid?: Maybe; }; /** order by min() on columns of table "notification_subscription" */ @@ -3494,7 +3490,6 @@ export type Notification_Subscription_Min_Order_By = { id?: InputMaybe; p256dh?: InputMaybe; updatedAt?: InputMaybe; - uuid?: InputMaybe; }; /** response of any mutation on the table "notification_subscription" */ @@ -3523,7 +3518,6 @@ export type Notification_Subscription_Order_By = { id?: InputMaybe; p256dh?: InputMaybe; updatedAt?: InputMaybe; - uuid?: InputMaybe; }; /** primary key columns input for table: notification_subscription */ @@ -3546,9 +3540,7 @@ export enum Notification_Subscription_Select_Column { /** column name */ P256dh = 'p256dh', /** column name */ - UpdatedAt = 'updatedAt', - /** column name */ - Uuid = 'uuid' + UpdatedAt = 'updatedAt' } /** input type for updating data in table "notification_subscription" */ @@ -3560,7 +3552,6 @@ export type Notification_Subscription_Set_Input = { id?: InputMaybe; p256dh?: InputMaybe; updatedAt?: InputMaybe; - uuid?: InputMaybe; }; /** Streaming cursor of the table "notification_subscription" */ @@ -3580,7 +3571,6 @@ export type Notification_Subscription_Stream_Cursor_Value_Input = { id?: InputMaybe; p256dh?: InputMaybe; updatedAt?: InputMaybe; - uuid?: InputMaybe; }; /** update columns of table "notification_subscription" */ @@ -3598,9 +3588,7 @@ export enum Notification_Subscription_Update_Column { /** column name */ P256dh = 'p256dh', /** column name */ - UpdatedAt = 'updatedAt', - /** column name */ - Uuid = 'uuid' + UpdatedAt = 'updatedAt' } export type Notification_Subscription_Updates = { diff --git a/backend/zeus/src/zeus/const.ts b/backend/zeus/src/zeus/const.ts index 063a1c16..5c22e3bc 100644 --- a/backend/zeus/src/zeus/const.ts +++ b/backend/zeus/src/zeus/const.ts @@ -755,8 +755,8 @@ export const AllTypesProps: Record = { _or: "friendship_bool_exp", chats: "chat_bool_exp", chats_aggregate: "chat_aggregate_bool_exp", - client1: "client_bool_exp", - client2: "client_bool_exp", + client: "client_bool_exp", + clientByClientid2: "client_bool_exp", clientId1: "uuid_comparison_exp", clientId2: "uuid_comparison_exp", createdAt: "timestamptz_comparison_exp", @@ -767,8 +767,8 @@ export const AllTypesProps: Record = { friendship_constraint: "enum" as const, friendship_insert_input: { chats: "chat_arr_rel_insert_input", - client1: "client_obj_rel_insert_input", - client2: "client_obj_rel_insert_input", + client: "client_obj_rel_insert_input", + clientByClientid2: "client_obj_rel_insert_input", clientId1: "uuid", clientId2: "uuid", createdAt: "timestamptz", @@ -802,8 +802,8 @@ export const AllTypesProps: Record = { }, friendship_order_by: { chats_aggregate: "chat_aggregate_order_by", - client1: "client_order_by", - client2: "client_order_by", + client: "client_order_by", + clientByClientid2: "client_order_by", clientId1: "order_by", clientId2: "order_by", createdAt: "order_by", @@ -2744,8 +2744,8 @@ export const ReturnTypes: Record = { friendship: { chats: "chat", chats_aggregate: "chat_aggregate", - client1: "client", - client2: "client", + client: "client", + clientByClientid2: "client", clientId1: "uuid", clientId2: "uuid", createdAt: "timestamptz", diff --git a/backend/zeus/src/zeus/index.ts b/backend/zeus/src/zeus/index.ts index 8bd1bb9a..52546988 100644 --- a/backend/zeus/src/zeus/index.ts +++ b/backend/zeus/src/zeus/index.ts @@ -4279,9 +4279,9 @@ export type ValueTypes = { ValueTypes["chat_aggregate"], ]; /** An object relationship */ - client1?: ValueTypes["client"]; + client?: ValueTypes["client"]; /** An object relationship */ - client2?: ValueTypes["client"]; + clientByClientid2?: ValueTypes["client"]; clientId1?: boolean | `@${string}`; clientId2?: boolean | `@${string}`; createdAt?: boolean | `@${string}`; @@ -4385,12 +4385,12 @@ export type ValueTypes = { | undefined | null | Variable; - client1?: + client?: | ValueTypes["client_bool_exp"] | undefined | null | Variable; - client2?: + clientByClientid2?: | ValueTypes["client_bool_exp"] | undefined | null @@ -4435,12 +4435,12 @@ export type ValueTypes = { | undefined | null | Variable; - client1?: + client?: | ValueTypes["client_obj_rel_insert_input"] | undefined | null | Variable; - client2?: + clientByClientid2?: | ValueTypes["client_obj_rel_insert_input"] | undefined | null @@ -4567,12 +4567,12 @@ export type ValueTypes = { | undefined | null | Variable; - client1?: + client?: | ValueTypes["client_order_by"] | undefined | null | Variable; - client2?: + clientByClientid2?: | ValueTypes["client_order_by"] | undefined | null @@ -12215,9 +12215,9 @@ export type ResolverInputTypes = { ResolverInputTypes["chat_aggregate"], ]; /** An object relationship */ - client1?: ResolverInputTypes["client"]; + client?: ResolverInputTypes["client"]; /** An object relationship */ - client2?: ResolverInputTypes["client"]; + clientByClientid2?: ResolverInputTypes["client"]; clientId1?: boolean | `@${string}`; clientId2?: boolean | `@${string}`; createdAt?: boolean | `@${string}`; @@ -12288,8 +12288,11 @@ export type ResolverInputTypes = { | ResolverInputTypes["chat_aggregate_bool_exp"] | undefined | null; - client1?: ResolverInputTypes["client_bool_exp"] | undefined | null; - client2?: ResolverInputTypes["client_bool_exp"] | undefined | null; + client?: ResolverInputTypes["client_bool_exp"] | undefined | null; + clientByClientid2?: + | ResolverInputTypes["client_bool_exp"] + | undefined + | null; clientId1?: ResolverInputTypes["uuid_comparison_exp"] | undefined | null; clientId2?: ResolverInputTypes["uuid_comparison_exp"] | undefined | null; createdAt?: @@ -12308,11 +12311,11 @@ export type ResolverInputTypes = { /** input type for inserting data into table "friendship" */ ["friendship_insert_input"]: { chats?: ResolverInputTypes["chat_arr_rel_insert_input"] | undefined | null; - client1?: + client?: | ResolverInputTypes["client_obj_rel_insert_input"] | undefined | null; - client2?: + clientByClientid2?: | ResolverInputTypes["client_obj_rel_insert_input"] | undefined | null; @@ -12390,8 +12393,11 @@ export type ResolverInputTypes = { | ResolverInputTypes["chat_aggregate_order_by"] | undefined | null; - client1?: ResolverInputTypes["client_order_by"] | undefined | null; - client2?: ResolverInputTypes["client_order_by"] | undefined | null; + client?: ResolverInputTypes["client_order_by"] | undefined | null; + clientByClientid2?: + | ResolverInputTypes["client_order_by"] + | undefined + | null; clientId1?: ResolverInputTypes["order_by"] | undefined | null; clientId2?: ResolverInputTypes["order_by"] | undefined | null; createdAt?: ResolverInputTypes["order_by"] | undefined | null; @@ -17573,9 +17579,9 @@ export type ModelTypes = { /** An aggregate relationship */ chats_aggregate: ModelTypes["chat_aggregate"]; /** An object relationship */ - client1: ModelTypes["client"]; + client: ModelTypes["client"]; /** An object relationship */ - client2: ModelTypes["client"]; + clientByClientid2: ModelTypes["client"]; clientId1: ModelTypes["uuid"]; clientId2: ModelTypes["uuid"]; createdAt: ModelTypes["timestamptz"]; @@ -17622,8 +17628,8 @@ export type ModelTypes = { _or?: Array | undefined; chats?: ModelTypes["chat_bool_exp"] | undefined; chats_aggregate?: ModelTypes["chat_aggregate_bool_exp"] | undefined; - client1?: ModelTypes["client_bool_exp"] | undefined; - client2?: ModelTypes["client_bool_exp"] | undefined; + client?: ModelTypes["client_bool_exp"] | undefined; + clientByClientid2?: ModelTypes["client_bool_exp"] | undefined; clientId1?: ModelTypes["uuid_comparison_exp"] | undefined; clientId2?: ModelTypes["uuid_comparison_exp"] | undefined; createdAt?: ModelTypes["timestamptz_comparison_exp"] | undefined; @@ -17635,8 +17641,8 @@ export type ModelTypes = { /** input type for inserting data into table "friendship" */ ["friendship_insert_input"]: { chats?: ModelTypes["chat_arr_rel_insert_input"] | undefined; - client1?: ModelTypes["client_obj_rel_insert_input"] | undefined; - client2?: ModelTypes["client_obj_rel_insert_input"] | undefined; + client?: ModelTypes["client_obj_rel_insert_input"] | undefined; + clientByClientid2?: ModelTypes["client_obj_rel_insert_input"] | undefined; clientId1?: ModelTypes["uuid"] | undefined; clientId2?: ModelTypes["uuid"] | undefined; createdAt?: ModelTypes["timestamptz"] | undefined; @@ -17702,8 +17708,8 @@ export type ModelTypes = { /** Ordering options when selecting data from "friendship". */ ["friendship_order_by"]: { chats_aggregate?: ModelTypes["chat_aggregate_order_by"] | undefined; - client1?: ModelTypes["client_order_by"] | undefined; - client2?: ModelTypes["client_order_by"] | undefined; + client?: ModelTypes["client_order_by"] | undefined; + clientByClientid2?: ModelTypes["client_order_by"] | undefined; clientId1?: ModelTypes["order_by"] | undefined; clientId2?: ModelTypes["order_by"] | undefined; createdAt?: ModelTypes["order_by"] | undefined; @@ -20942,9 +20948,9 @@ export type GraphQLTypes = { /** An aggregate relationship */ chats_aggregate: GraphQLTypes["chat_aggregate"]; /** An object relationship */ - client1: GraphQLTypes["client"]; + client: GraphQLTypes["client"]; /** An object relationship */ - client2: GraphQLTypes["client"]; + clientByClientid2: GraphQLTypes["client"]; clientId1: GraphQLTypes["uuid"]; clientId2: GraphQLTypes["uuid"]; createdAt: GraphQLTypes["timestamptz"]; @@ -20993,8 +20999,8 @@ export type GraphQLTypes = { _or?: Array | undefined; chats?: GraphQLTypes["chat_bool_exp"] | undefined; chats_aggregate?: GraphQLTypes["chat_aggregate_bool_exp"] | undefined; - client1?: GraphQLTypes["client_bool_exp"] | undefined; - client2?: GraphQLTypes["client_bool_exp"] | undefined; + client?: GraphQLTypes["client_bool_exp"] | undefined; + clientByClientid2?: GraphQLTypes["client_bool_exp"] | undefined; clientId1?: GraphQLTypes["uuid_comparison_exp"] | undefined; clientId2?: GraphQLTypes["uuid_comparison_exp"] | undefined; createdAt?: GraphQLTypes["timestamptz_comparison_exp"] | undefined; @@ -21007,8 +21013,8 @@ export type GraphQLTypes = { /** input type for inserting data into table "friendship" */ ["friendship_insert_input"]: { chats?: GraphQLTypes["chat_arr_rel_insert_input"] | undefined; - client1?: GraphQLTypes["client_obj_rel_insert_input"] | undefined; - client2?: GraphQLTypes["client_obj_rel_insert_input"] | undefined; + client?: GraphQLTypes["client_obj_rel_insert_input"] | undefined; + clientByClientid2?: GraphQLTypes["client_obj_rel_insert_input"] | undefined; clientId1?: GraphQLTypes["uuid"] | undefined; clientId2?: GraphQLTypes["uuid"] | undefined; createdAt?: GraphQLTypes["timestamptz"] | undefined; @@ -21077,8 +21083,8 @@ export type GraphQLTypes = { /** Ordering options when selecting data from "friendship". */ ["friendship_order_by"]: { chats_aggregate?: GraphQLTypes["chat_aggregate_order_by"] | undefined; - client1?: GraphQLTypes["client_order_by"] | undefined; - client2?: GraphQLTypes["client_order_by"] | undefined; + client?: GraphQLTypes["client_order_by"] | undefined; + clientByClientid2?: GraphQLTypes["client_order_by"] | undefined; clientId1?: GraphQLTypes["order_by"] | undefined; clientId2?: GraphQLTypes["order_by"] | undefined; createdAt?: GraphQLTypes["order_by"] | undefined; diff --git a/packages/recoil/src/atoms/account.tsx b/packages/recoil/src/atoms/account.tsx index ee0e4f37..b7f4da55 100644 --- a/packages/recoil/src/atoms/account.tsx +++ b/packages/recoil/src/atoms/account.tsx @@ -1,5 +1,6 @@ -import { AccountType } from "@paybox/common"; -import { atom } from "recoil"; +import { AccountType, BACKEND_URL, responseStatus } from "@paybox/common"; +import { atom, selector } from "recoil"; +import { clientAtom } from "./client"; export const accountAtom = atom({ default: null, @@ -15,4 +16,28 @@ export const accountsAtom = atom({ export const defaultAccountNumberAtom = atom({ default: 1, key: "defaultAccountNumberAtom", +}); + +export const getAccountNumber = selector({ + key: 'getAccountNumber', + get: async ({ get }) => { + const jwt = get(clientAtom)?.jwt; + try { + const {status, putUrl, number}: {status: responseStatus, putUrl: string, number: number} = await fetch(`${BACKEND_URL}/account/defaultMetadata`, { + method: "get", + headers: { + "Content-type": "application/json", + //@ts-ignore + "Authorization": `Bearer ${jwt}` + } + }).then(res => res.json()); + if(status == responseStatus.Error) { + return 1; + } + return number + 1; + } catch (error) { + console.error(error) + return 1; + } + }, }); \ No newline at end of file From efb2ca9d0c961a97d35090aa7022f0f8f18101bb Mon Sep 17 00:00:00 2001 From: Akash Shaw Date: Fri, 29 Mar 2024 21:42:15 +0530 Subject: [PATCH 02/10] chore: adding some atoms for account operations --- packages/recoil/src/atoms/account.tsx | 8 ++++++++ yarn.lock | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/recoil/src/atoms/account.tsx b/packages/recoil/src/atoms/account.tsx index b7f4da55..95fa8892 100644 --- a/packages/recoil/src/atoms/account.tsx +++ b/packages/recoil/src/atoms/account.tsx @@ -40,4 +40,12 @@ export const getAccountNumber = selector({ return 1; } }, +}); + +export const accountPrivateKeysAtom = atom<{ + network: "Solana" | "Ethereum", + privateKey: string, +}[]>({ + default: [], + key: "accountPrivateKeysAtom", }); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index b62b2c2a..f8dc72f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10148,7 +10148,7 @@ crypto-js@^4.1.1: crypto@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== cssesc@^3.0.0: From 6d3b082fb5b882c8056c3e799144f1893b146e85 Mon Sep 17 00:00:00 2001 From: Akash Shaw Date: Fri, 29 Mar 2024 21:42:58 +0530 Subject: [PATCH 03/10] chore: changing the getPrivate validate not to take network --- packages/common/src/validations/account.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/common/src/validations/account.ts b/packages/common/src/validations/account.ts index 3233ec7f..2dead34a 100644 --- a/packages/common/src/validations/account.ts +++ b/packages/common/src/validations/account.ts @@ -44,7 +44,6 @@ export const AccountGetPrivateKey = z.object({ /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/, "should be a valid UUID.", ), - network: z.nativeEnum(Network), }); export const AccountDelete = z.object({ From 6a8a0f3049bf9893a8d4ef432b0e9cf3634af4af Mon Sep 17 00:00:00 2001 From: Akash Shaw Date: Fri, 29 Mar 2024 21:44:48 +0530 Subject: [PATCH 04/10] chore: encrypt and decrypt function for private keys --- apps/web/lib/config.ts | 5 ++- apps/web/lib/helper.ts | 35 ++++++++++++++++++++- backend/api/src/auth/util.ts | 61 ++++++++++++++++++++++++++++++++++-- backend/api/src/config.ts | 5 ++- 4 files changed, 101 insertions(+), 5 deletions(-) diff --git a/apps/web/lib/config.ts b/apps/web/lib/config.ts index e7c5da64..36f67d67 100644 --- a/apps/web/lib/config.ts +++ b/apps/web/lib/config.ts @@ -1,4 +1,7 @@ import { VAPID_PUBLIC_KEY_DEFAULT } from "@paybox/common"; export const VAPID_PUBLIC_KEY = - process.env.VAPID_PUBLIC_KEY || VAPID_PUBLIC_KEY_DEFAULT; \ No newline at end of file + process.env.VAPID_PUBLIC_KEY || VAPID_PUBLIC_KEY_DEFAULT; + +export const PRIVATE_KEY_ENCRYPTION_KEY = + process.env.PRIVATE_KEY_ENCRYPTION_KEY || "e53e0e6fb7120f8793e0127371f6265a52e9baecdbf3e336f7965a6b5bad9282"; \ No newline at end of file diff --git a/apps/web/lib/helper.ts b/apps/web/lib/helper.ts index f63e4fa7..0ece5c17 100644 --- a/apps/web/lib/helper.ts +++ b/apps/web/lib/helper.ts @@ -1,4 +1,5 @@ - +import crypto from 'crypto'; +import { PRIVATE_KEY_ENCRYPTION_KEY } from './config'; export function toBase64(file: File) { return new Promise((resolve, reject) => { @@ -40,4 +41,36 @@ export function urlBase64ToUint8Array(base64String: string) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; +} + +const commonEncryptionKey = crypto + .createHash('sha256') + .update(PRIVATE_KEY_ENCRYPTION_KEY) + .digest(); + + +/** + * + * @param encryptedPrivateKey + * @param password + * @returns + */ +export const decryptWithPassword = ( + encryptedPrivateKey: string, + password: string, +): string => { + const [iv, commonCipherIv, encrypted] = encryptedPrivateKey.split(':'); + + const hashedPassword = crypto.createHash('sha256').update(password).digest(); + const commonDecipher = crypto.createDecipheriv('aes-256-cbc', commonEncryptionKey, Buffer.from(commonCipherIv, 'hex')); + + let decryptedPrivateKey = commonDecipher.update(encrypted, 'hex', 'hex'); + decryptedPrivateKey += commonDecipher.final('hex'); + + const decipher = crypto.createDecipheriv('aes-256-cbc', hashedPassword, Buffer.from(iv, 'hex')); + + let privateKey = decipher.update(decryptedPrivateKey, 'hex', 'utf8'); + privateKey += decipher.final('utf8'); + + return privateKey; } \ No newline at end of file diff --git a/backend/api/src/auth/util.ts b/backend/api/src/auth/util.ts index ff25ac0d..9c97f336 100644 --- a/backend/api/src/auth/util.ts +++ b/backend/api/src/auth/util.ts @@ -1,7 +1,7 @@ import { response, type Request, type Response } from "express"; import { importPKCS8, importSPKI, jwtVerify, SignJWT } from "jose"; import bcryptjs from "bcryptjs"; -import { AUTH_JWT_PRIVATE_KEY, AUTH_JWT_PUBLIC_KEY, GMAIL, TWILLO_NUMBER } from "../config"; +import { AUTH_JWT_PRIVATE_KEY, AUTH_JWT_PUBLIC_KEY, GMAIL, PRIVATE_KEY_ENCRYPTION_KEY, TWILLO_NUMBER } from "../config"; import { Address, CLIENT_URL, @@ -275,7 +275,7 @@ export const updateKey = async (bucketName: string, key: string, newKey: string) // 'Upload-Date': new Date().toISOString(), 'owner': 'paybox' } - }) ; + }); const deleteCommand = new DeleteObjectCommand({ Bucket: bucketName, @@ -296,3 +296,60 @@ export const calculateGas = (gasLimit: BigInt, gasPrice: BigInt): number => { const maxGasFeeInWei = Number(gasLimit) * Number(gasPrice); return maxGasFeeInWei / 1e18; }; + +const commonEncryptionKey = crypto + .createHash('sha256') + .update(PRIVATE_KEY_ENCRYPTION_KEY) + .digest(); + +/** + * + * @param privateKey + * @param password + * @returns + */ +export const encryptWithPassword = ( + privateKey: string, + password: string, +): string => { + const hashedPassword = crypto.createHash('sha256').update(password).digest(); + const iv = crypto.randomBytes(16); + const cipher = crypto.createCipheriv('aes-256-cbc', hashedPassword, iv); + + let encryptedPrivateKey = cipher.update(privateKey, 'utf8', 'hex'); + encryptedPrivateKey += cipher.final('hex'); + + const commonCipherIv = crypto.randomBytes(16); + const commonCipher = crypto.createCipheriv('aes-256-cbc', commonEncryptionKey, commonCipherIv); + + encryptedPrivateKey = commonCipher.update(encryptedPrivateKey, 'hex', 'hex'); + encryptedPrivateKey += commonCipher.final('hex'); + + return iv.toString('hex') + ':' + commonCipherIv.toString('hex') + ':' + encryptedPrivateKey; +} + +/** + * + * @param encryptedPrivateKey + * @param password + * @returns + */ +export const decryptWithPassword = ( + encryptedPrivateKey: string, + password: string, +): string => { + const [iv, commonCipherIv, encrypted] = encryptedPrivateKey.split(':'); + + const hashedPassword = crypto.createHash('sha256').update(password).digest(); + const commonDecipher = crypto.createDecipheriv('aes-256-cbc', commonEncryptionKey, Buffer.from(commonCipherIv, 'hex')); + + let decryptedPrivateKey = commonDecipher.update(encrypted, 'hex', 'hex'); + decryptedPrivateKey += commonDecipher.final('hex'); + + const decipher = crypto.createDecipheriv('aes-256-cbc', hashedPassword, Buffer.from(iv, 'hex')); + + let privateKey = decipher.update(decryptedPrivateKey, 'hex', 'utf8'); + privateKey += decipher.final('utf8'); + + return privateKey; +} \ No newline at end of file diff --git a/backend/api/src/config.ts b/backend/api/src/config.ts index 9012f3c7..998db0c5 100644 --- a/backend/api/src/config.ts +++ b/backend/api/src/config.ts @@ -74,4 +74,7 @@ export const CHAT_KAFKA_URL = process.env.CHAT_KAFKA_URL || KAFKA_URL; export const CHAT_KAFKA_ID = - process.env.CHAT_KAFKA_ID || KAFKA_CLIENT_ID; \ No newline at end of file + process.env.CHAT_KAFKA_ID || KAFKA_CLIENT_ID; + +export const PRIVATE_KEY_ENCRYPTION_KEY = + process.env.PRIVATE_KEY_ENCRYPTION_KEY || "e53e0e6fb7120f8793e0127371f6265a52e9baecdbf3e336f7965a6b5bad9282"; \ No newline at end of file From 7d7af8ef5b4c8e7531dbeb19f67571e4dddd341d Mon Sep 17 00:00:00 2001 From: Akash Shaw Date: Fri, 29 Mar 2024 21:45:36 +0530 Subject: [PATCH 05/10] chore: querying all the networks in a given accoutn for privatekey --- backend/backend-common/src/db/account.ts | 60 +++++++++++++----------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/backend/backend-common/src/db/account.ts b/backend/backend-common/src/db/account.ts index 383aad18..19f68cf5 100644 --- a/backend/backend-common/src/db/account.ts +++ b/backend/backend-common/src/db/account.ts @@ -185,41 +185,45 @@ export const updateAccountName = async ( */ export const getPrivate = async ( accountId: string, - network: Network, ): Promise<{ status: dbResStatus; - privateKey?: string; -}> => { - const returning = { - [network]: { - privateKey: true, - }, + sol?: { + privateKey: string }; - const response = await chain("query")( - { - account: [ - { - where: { - id: { _eq: accountId }, - }, - }, - returning, - ], - }, - { operationName: "getPrivate" }, - ); - //@ts-ignore - if (response.account[0][network]?.privateKey) { + eth?: { + privateKey: string + } +}> => { + const response = await chain("query")({ + account: [{ + limit: 1, + where: { + id: { _eq: accountId } + } + }, { + sol: { + privateKey: true + }, + eth: { + privateKey: true + }, + }] + }); + if (response.account[0].eth?.privateKey && response.account[0].sol?.privateKey) { return { status: dbResStatus.Ok, - //@ts-ignore - privateKey: response.account[0][network]?.privateKey, - }; - } + sol: { + privateKey: response.account[0].sol.privateKey as string + }, + eth: { + privateKey: response.account[0].eth.privateKey as string + } + } + }; return { status: dbResStatus.Error, }; -}; +} /** * Remove Account @@ -353,7 +357,7 @@ export const getAccounts = async ( order_by: [{ createdAt: order_by["asc"] }] - }, + }, { id: true, eth: { From d5cdd0f5ac8ebb8b92106d037e6f181ffad2618e Mon Sep 17 00:00:00 2001 From: Akash Shaw Date: Fri, 29 Mar 2024 21:46:05 +0530 Subject: [PATCH 06/10] chore: encryting the private keys --- backend/api/src/sockets/eth.ts | 13 +++++++------ backend/api/src/sockets/sol.ts | 15 +++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/backend/api/src/sockets/eth.ts b/backend/api/src/sockets/eth.ts index a3fe5025..1f23033e 100644 --- a/backend/api/src/sockets/eth.ts +++ b/backend/api/src/sockets/eth.ts @@ -17,6 +17,7 @@ import { } from "@paybox/common"; import { EthNetwok } from "../types/address"; import { INFURA_PROJECT_ID } from "../config"; +import { encryptWithPassword } from "../auth"; interface EthereumTransactionData { @@ -50,11 +51,11 @@ export class EthOps { * @param secretPhrase * @returns */ - createWallet(secretPhrase: string): WalletKeys { + createWallet(secretPhrase: string, hashPassword: string): WalletKeys { const wallet = ethers.Wallet.fromPhrase(secretPhrase); const keys: WalletKeys = { - privateKey: wallet.privateKey, + privateKey: encryptWithPassword(wallet.privateKey, hashPassword), publicKey: wallet.address, }; return keys; @@ -65,7 +66,7 @@ export class EthOps { * @param secretPhrase * @returns */ - createAccount(secretPhrase: string): WalletKeys { + createAccount(secretPhrase: string, hashPassword: string): WalletKeys { const accountIndex = Math.round(Date.now() / 1000); const path = `m/44'/60'/${accountIndex}'/0/0`; const wallet = ethers.HDNodeWallet.fromPhrase( @@ -75,7 +76,7 @@ export class EthOps { ); const keys: WalletKeys = { - privateKey: wallet.privateKey, + privateKey: encryptWithPassword(wallet.privateKey, hashPassword), publicKey: wallet.address, }; return keys; @@ -110,11 +111,11 @@ export class EthOps { * @param secretKey * @returns */ - fromSecret(secretKey: string): WalletKeys { + fromSecret(secretKey: string, hashPassword: string): WalletKeys { const wallet = new ethers.Wallet(secretKey); const keys: WalletKeys = { - privateKey: wallet.privateKey, + privateKey: encryptWithPassword(wallet.privateKey, hashPassword), publicKey: wallet.address, }; return keys; diff --git a/backend/api/src/sockets/sol.ts b/backend/api/src/sockets/sol.ts index 33fc6810..e7ad5771 100644 --- a/backend/api/src/sockets/sol.ts +++ b/backend/api/src/sockets/sol.ts @@ -28,6 +28,7 @@ import { import bs58 from "bs58"; import * as bip32 from "bip32"; import { derivePath } from "ed25519-hd-key"; +import { encryptWithPassword } from "../auth"; export class SolOps { private connection: Connection; @@ -38,24 +39,26 @@ export class SolOps { this.connection = new Connection(this.rpcUrl, "confirmed"); } - async createWallet(secretPhrase: string): Promise { + async createWallet(secretPhrase: string, hashPassword: string): Promise { const seedBuffer = await bip39.mnemonicToSeed(secretPhrase); const seedKeyArray = Uint8Array.from(seedBuffer.subarray(0, 32)); const keyPair = Keypair.fromSeed(seedKeyArray); + return { publicKey: keyPair.publicKey.toBase58(), - privateKey: base58.encode(keyPair.secretKey), + privateKey: encryptWithPassword(base58.encode(keyPair.secretKey), hashPassword), }; } - async createAccount(secretPhrase: string): Promise { + async createAccount(secretPhrase: string, hashPassword: string): Promise { const accountIndex = Math.round(Date.now() / 1000); const path = `m/44'/501'/${accountIndex}'/0'`; const derivedSeed = derivePath(path, secretPhrase).key; const keyPair = Keypair.fromSeed(derivedSeed); + console.log('from back', base58.encode(keyPair.secretKey)); return { publicKey: keyPair.publicKey.toBase58(), - privateKey: base58.encode(keyPair.secretKey), + privateKey: encryptWithPassword(base58.encode(keyPair.secretKey), hashPassword), }; } @@ -80,7 +83,7 @@ export class SolOps { return accounts; } - async fromSecret(secretKey: string): Promise { + async fromSecret(secretKey: string, hashPassword: string): Promise { const decodedBytes = bs58.decode(secretKey); console.log(decodedBytes); const privateKeyArray = new Uint8Array(decodedBytes); @@ -88,7 +91,7 @@ export class SolOps { const keyPair = Keypair.fromSecretKey(decodedBytes); return { publicKey: keyPair.publicKey.toBase58(), - privateKey: base58.encode(keyPair.secretKey), + privateKey: encryptWithPassword(base58.encode(keyPair.secretKey), hashPassword), }; } From 9bb31061f1ef4d38376bab75ac1127d386327905 Mon Sep 17 00:00:00 2001 From: Akash Shaw Date: Fri, 29 Mar 2024 21:46:26 +0530 Subject: [PATCH 07/10] Chore: api change --- backend/api/src/routes/account.ts | 43 +++++++++++++++++++++++++------ backend/api/src/routes/client.ts | 33 +++++++++++++++--------- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/backend/api/src/routes/account.ts b/backend/api/src/routes/account.ts index fb108bf5..6066eb64 100644 --- a/backend/api/src/routes/account.ts +++ b/backend/api/src/routes/account.ts @@ -56,6 +56,14 @@ accountRouter.post("/", accountCreateRateLimit, async (req, res) => { if (id) { const { name, imgUrl } = AccountCreateQuery.parse(req.query); + let hashPassword = (await Redis.getRedisInst().clientCache.getClientCache(id))?.password + || (await getPassword(id)).hashPassword; + if (!hashPassword) { + return res + .status(404) + .json({ status: responseStatus.Error, msg: "Account Not Found" }); + } + /** * Create an public and private key */ @@ -65,8 +73,8 @@ accountRouter.post("/", accountCreateRateLimit, async (req, res) => { .status(503) .json({ msg: "Database Error", status: responseStatus.Error }); } - const solKeys = await (new SolOps()).createAccount(query.secretPhase); - const ethKeys = (new EthOps()).createAccount(query.secretPhase); + const solKeys = await (new SolOps()).createAccount(query.secretPhase, hashPassword); + const ethKeys = (new EthOps()).createAccount(query.secretPhase, hashPassword); const mutation = await createAccount( id, query.id, @@ -164,17 +172,27 @@ accountRouter.post("/privateKey", checkPassword, async (req, res) => { //@ts-ignore const id = req.id; if (id) { - const { network, accountId } = AccountGetPrivateKey.parse(req.body); + const { accountId } = AccountGetPrivateKey.parse(req.body); + + let hashPassword = (await Redis.getRedisInst().clientCache.getClientCache(id))?.password + || (await getPassword(id)).hashPassword; + if (!hashPassword) { + return res + .status(404) + .json({ status: responseStatus.Error, msg: "Account Not Found" }); + } - const query = await getPrivate(accountId, network); - if (query.status == dbResStatus.Error || query.privateKey == undefined) { + const query = await getPrivate(accountId); + if (query.status == dbResStatus.Error || query.sol == undefined || query.eth == undefined) { return res .status(503) .json({ msg: "Database Error", status: responseStatus.Error }); } return res.status(200).json({ status: responseStatus.Ok, - privateKey: query.privateKey, + sol: query.sol, + eth: query.eth, + hashPassword, }); } return res @@ -278,12 +296,21 @@ accountRouter.post("/private", async (req, res) => { const id = req.id; if (id) { const { secretKey, name, network } = ImportAccountSecret.parse(req.query); + + let hashPassword = (await Redis.getRedisInst().clientCache.getClientCache(id))?.password + || (await getPassword(id)).hashPassword; + if (!hashPassword) { + return res + .status(404) + .json({ status: responseStatus.Error, msg: "Account Not Found" }); + } + let keys = {} as WalletKeys; switch (network) { case Network.Sol: - keys = await (new SolOps()).fromSecret(secretKey); + keys = await (new SolOps()).fromSecret(secretKey, hashPassword); case Network.Eth: - keys = (new EthOps).fromSecret(secretKey); + keys = (new EthOps).fromSecret(secretKey, hashPassword); case Network.Bitcoin: case Network.USDC: break; diff --git a/backend/api/src/routes/client.ts b/backend/api/src/routes/client.ts index a924275b..f069a8b0 100644 --- a/backend/api/src/routes/client.ts +++ b/backend/api/src/routes/client.ts @@ -30,11 +30,12 @@ import { updatePassword, validateClient, genRand, - checkPassword, - extractClientId, + checkPassword, + extractClientId, isValidated, validatePassword, setJWTCookie, + getPassword, } from "@paybox/backend-common"; import { Redis } from "../index"; import { @@ -43,7 +44,7 @@ import { sendOTP, setHashPassword, } from "../auth/util"; -import { resendOtpLimiter } from "../auth/middleware"; +import { resendOtpLimiter } from "../auth/middleware"; import { Client, ClientSigninFormValidate, @@ -144,9 +145,17 @@ clientRouter.patch("/valid", extractClientId, isValidated, async (req, res) => { .json({ msg: "Invalid otp 🥲", status: responseStatus.Error }); } + let hashPassword = (await Redis.getRedisInst().clientCache.getClientCache(tempCache))?.password + || (await getPassword(tempCache)).hashPassword; + if (!hashPassword) { + return res + .status(404) + .json({ status: responseStatus.Error, msg: "Account Not Found" }); + } + const seed = generateSeed(SECRET_PHASE_STRENGTH); - const solKeys = await (new SolOps()).createWallet(seed); - const ethKeys = (new EthOps()).createWallet(seed); + const solKeys = await (new SolOps()).createWallet(seed, hashPassword); + const ethKeys = (new EthOps()).createWallet(seed, hashPassword); const validate = await validateClient(id, seed, 'Account 1', solKeys, ethKeys); if (validate.status == dbResStatus.Error || validate.walletId == undefined || validate.account == undefined) { @@ -162,12 +171,12 @@ clientRouter.patch("/valid", extractClientId, isValidated, async (req, res) => { /** * Cache */ - await Redis.getRedisInst().wallet.handleValid({ - id: validate.walletId, - clientId: id, - accounts: [validate.account], - }, id, validate.account); - + await Redis.getRedisInst().wallet.handleValid({ + id: validate.walletId, + clientId: id, + accounts: [validate.account], + }, id, validate.account); + return res .status(200) .json({ @@ -248,7 +257,7 @@ clientRouter.post("/providerAuth", async (req, res) => { /** * Check password */ - if(password) { + if (password) { const isCorrectPass = await validatePassword( password, client.password as string, From 66f89577f423976bd3cae8cb074ffb47221a519f Mon Sep 17 00:00:00 2001 From: Akash Shaw Date: Fri, 29 Mar 2024 21:46:56 +0530 Subject: [PATCH 08/10] chore: private key page for account --- .../[id]/privatekey/components/alert-msg.tsx | 25 ++++ .../privatekey/components/key-dialog-box.tsx | 121 +++++++++++++++ .../components/private-key-form.tsx | 140 ++++++++++++++++++ apps/web/app/account/[id]/privatekey/page.tsx | 57 ++++++- apps/web/package.json | 1 + 5 files changed, 341 insertions(+), 3 deletions(-) create mode 100644 apps/web/app/account/[id]/privatekey/components/alert-msg.tsx create mode 100644 apps/web/app/account/[id]/privatekey/components/key-dialog-box.tsx create mode 100644 apps/web/app/account/[id]/privatekey/components/private-key-form.tsx diff --git a/apps/web/app/account/[id]/privatekey/components/alert-msg.tsx b/apps/web/app/account/[id]/privatekey/components/alert-msg.tsx new file mode 100644 index 00000000..6c61863c --- /dev/null +++ b/apps/web/app/account/[id]/privatekey/components/alert-msg.tsx @@ -0,0 +1,25 @@ +import { + Alert, + AlertDescription, + AlertTitle, +} from "@/components/ui/alert" +import { RocketIcon } from "lucide-react" + +export function AlertMsg({ + message, + title = "Heads up!", + variant = "default", +}: { + message: string + title?: string + variant?: "default" | "destructive", +}) { + return ( + + + {title} + {message} + + ) + +} \ No newline at end of file diff --git a/apps/web/app/account/[id]/privatekey/components/key-dialog-box.tsx b/apps/web/app/account/[id]/privatekey/components/key-dialog-box.tsx new file mode 100644 index 00000000..71343be8 --- /dev/null +++ b/apps/web/app/account/[id]/privatekey/components/key-dialog-box.tsx @@ -0,0 +1,121 @@ +import { CopyIcon } from "@radix-ui/react-icons" + +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" +import { AlertTriangle } from 'lucide-react'; +import { + Card, + CardContent, + CardHeader, +} from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/components/ui/tabs" +import { Textarea } from "@/components/ui/textarea"; +import React from "react"; +import { useRecoilValue } from "recoil"; +import { accountPrivateKeysAtom } from "@paybox/recoil"; + +export function PrivateKeyDialogBox({ + open, + setOpen, + // keys, +}: { + open: boolean, + setOpen: (open: boolean) => void, + // keys: { network: string, privateKey: string }[] +}) { + const keys = useRecoilValue(accountPrivateKeysAtom); + const [copyText, setCopyText] = React.useState("Copy") + + return ( + + + + + + + {keys.map((key, index) => ( + + {key.network} + + ))} + + + + + + + + + {keys.map((key, index) => ( + + + + + + Caution! + Do not share your private keys. Indiviual bearing this has full control on this account! + + + +
+
+ +