diff --git a/api/functions/graphql/nexus-typegen.ts b/api/functions/graphql/nexus-typegen.ts index b3b9805..f9955e3 100644 --- a/api/functions/graphql/nexus-typegen.ts +++ b/api/functions/graphql/nexus-typegen.ts @@ -28,15 +28,7 @@ declare global { } export interface NexusGenInputs { - StoryInputType: { // input type - body: string; // String! - cover_image?: string | null; // String - id?: number | null; // Int - is_published?: boolean | null; // Boolean - tags: string[]; // [String!]! - title: string; // String! - } - UpdateProfileInput: { // input type + ProfileDetailsInput: { // input type avatar?: string | null; // String bio?: string | null; // String email?: string | null; // String @@ -49,6 +41,14 @@ export interface NexusGenInputs { twitter?: string | null; // String website?: string | null; // String } + StoryInputType: { // input type + body: string; // String! + cover_image?: string | null; // String + id?: number | null; // Int + is_published?: boolean | null; // Boolean + tags: string[]; // [String!]! + title: string; // String! + } UserKeyInputType: { // input type key: string; // String! name: string; // String! @@ -141,6 +141,24 @@ export interface NexusGenObjects { minSendable?: number | null; // Int } Mutation: {}; + MyProfile: { // root type + avatar: string; // String! + bio?: string | null; // String + email?: string | null; // String + github?: string | null; // String + id: number; // Int! + jobTitle?: string | null; // String + join_date: NexusGenScalars['Date']; // Date! + lightning_address?: string | null; // String + linkedin?: string | null; // String + location?: string | null; // String + name: string; // String! + nostr_prv_key?: string | null; // String + nostr_pub_key?: string | null; // String + role?: string | null; // String + twitter?: string | null; // String + website?: string | null; // String + } PostComment: { // root type author: NexusGenRootTypes['Author']; // Author! body: string; // String! @@ -202,16 +220,10 @@ export interface NexusGenObjects { linkedin?: string | null; // String location?: string | null; // String name: string; // String! - nostr_prv_key?: string | null; // String - nostr_pub_key?: string | null; // String role?: string | null; // String twitter?: string | null; // String website?: string | null; // String } - UserKey: { // root type - key: string; // String! - name: string; // String! - } Vote: { // root type amount_in_sat: number; // Int! id: number; // Int! @@ -221,9 +233,14 @@ export interface NexusGenObjects { payment_hash: string; // String! payment_request: string; // String! } + WalletKey: { // root type + key: string; // String! + name: string; // String! + } } export interface NexusGenInterfaces { + BaseUser: NexusGenRootTypes['MyProfile'] | NexusGenRootTypes['User']; PostBase: NexusGenRootTypes['Bounty'] | NexusGenRootTypes['Question'] | NexusGenRootTypes['Story']; } @@ -321,10 +338,30 @@ export interface NexusGenFieldTypes { createStory: NexusGenRootTypes['Story'] | null; // Story deleteStory: NexusGenRootTypes['Story'] | null; // Story donate: NexusGenRootTypes['Donation']; // Donation! - updateProfile: NexusGenRootTypes['User'] | null; // User - updateUserWalletKeys: NexusGenRootTypes['UserKey'][]; // [UserKey!]! + updateProfileDetails: NexusGenRootTypes['MyProfile'] | null; // MyProfile + updateUserPreferences: NexusGenRootTypes['MyProfile'][]; // [MyProfile!]! vote: NexusGenRootTypes['Vote']; // Vote! } + MyProfile: { // field return type + avatar: string; // String! + bio: string | null; // String + email: string | null; // String + github: string | null; // String + id: number; // Int! + jobTitle: string | null; // String + join_date: NexusGenScalars['Date']; // Date! + lightning_address: string | null; // String + linkedin: string | null; // String + location: string | null; // String + name: string; // String! + nostr_prv_key: string | null; // String + nostr_pub_key: string | null; // String + role: string | null; // String + stories: NexusGenRootTypes['Story'][]; // [Story!]! + twitter: string | null; // String + walletsKeys: NexusGenRootTypes['WalletKey'][]; // [WalletKey!]! + website: string | null; // String + } PostComment: { // field return type author: NexusGenRootTypes['Author']; // Author! body: string; // String! @@ -361,8 +398,7 @@ export interface NexusGenFieldTypes { getProject: NexusGenRootTypes['Project']; // Project! getTrendingPosts: NexusGenRootTypes['Post'][]; // [Post!]! hottestProjects: NexusGenRootTypes['Project'][]; // [Project!]! - me: NexusGenRootTypes['User'] | null; // User - myWalletsKeys: NexusGenRootTypes['UserKey'][]; // [UserKey!]! + me: NexusGenRootTypes['MyProfile'] | null; // MyProfile newProjects: NexusGenRootTypes['Project'][]; // [Project!]! officialTags: NexusGenRootTypes['Tag'][]; // [Tag!]! popularTags: NexusGenRootTypes['Tag'][]; // [Tag!]! @@ -418,17 +454,11 @@ export interface NexusGenFieldTypes { linkedin: string | null; // String location: string | null; // String name: string; // String! - nostr_prv_key: string | null; // String - nostr_pub_key: string | null; // String role: string | null; // String stories: NexusGenRootTypes['Story'][]; // [Story!]! twitter: string | null; // String website: string | null; // String } - UserKey: { // field return type - key: string; // String! - name: string; // String! - } Vote: { // field return type amount_in_sat: number; // Int! id: number; // Int! @@ -438,6 +468,27 @@ export interface NexusGenFieldTypes { payment_hash: string; // String! payment_request: string; // String! } + WalletKey: { // field return type + key: string; // String! + name: string; // String! + } + BaseUser: { // field return type + avatar: string; // String! + bio: string | null; // String + email: string | null; // String + github: string | null; // String + id: number; // Int! + jobTitle: string | null; // String + join_date: NexusGenScalars['Date']; // Date! + lightning_address: string | null; // String + linkedin: string | null; // String + location: string | null; // String + name: string; // String! + role: string | null; // String + stories: NexusGenRootTypes['Story'][]; // [Story!]! + twitter: string | null; // String + website: string | null; // String + } PostBase: { // field return type body: string; // String! createdAt: NexusGenScalars['Date']; // Date! @@ -536,10 +587,30 @@ export interface NexusGenFieldTypeNames { createStory: 'Story' deleteStory: 'Story' donate: 'Donation' - updateProfile: 'User' - updateUserWalletKeys: 'UserKey' + updateProfileDetails: 'MyProfile' + updateUserPreferences: 'MyProfile' vote: 'Vote' } + MyProfile: { // field return type name + avatar: 'String' + bio: 'String' + email: 'String' + github: 'String' + id: 'Int' + jobTitle: 'String' + join_date: 'Date' + lightning_address: 'String' + linkedin: 'String' + location: 'String' + name: 'String' + nostr_prv_key: 'String' + nostr_pub_key: 'String' + role: 'String' + stories: 'Story' + twitter: 'String' + walletsKeys: 'WalletKey' + website: 'String' + } PostComment: { // field return type name author: 'Author' body: 'String' @@ -576,8 +647,7 @@ export interface NexusGenFieldTypeNames { getProject: 'Project' getTrendingPosts: 'Post' hottestProjects: 'Project' - me: 'User' - myWalletsKeys: 'UserKey' + me: 'MyProfile' newProjects: 'Project' officialTags: 'Tag' popularTags: 'Tag' @@ -633,17 +703,11 @@ export interface NexusGenFieldTypeNames { linkedin: 'String' location: 'String' name: 'String' - nostr_prv_key: 'String' - nostr_pub_key: 'String' role: 'String' stories: 'Story' twitter: 'String' website: 'String' } - UserKey: { // field return type name - key: 'String' - name: 'String' - } Vote: { // field return type name amount_in_sat: 'Int' id: 'Int' @@ -653,6 +717,27 @@ export interface NexusGenFieldTypeNames { payment_hash: 'String' payment_request: 'String' } + WalletKey: { // field return type name + key: 'String' + name: 'String' + } + BaseUser: { // field return type name + avatar: 'String' + bio: 'String' + email: 'String' + github: 'String' + id: 'Int' + jobTitle: 'String' + join_date: 'Date' + lightning_address: 'String' + linkedin: 'String' + location: 'String' + name: 'String' + role: 'String' + stories: 'Story' + twitter: 'String' + website: 'String' + } PostBase: { // field return type name body: 'String' createdAt: 'Date' @@ -684,11 +769,11 @@ export interface NexusGenArgTypes { donate: { // args amount_in_sat: number; // Int! } - updateProfile: { // args - data?: NexusGenInputs['UpdateProfileInput'] | null; // UpdateProfileInput + updateProfileDetails: { // args + data?: NexusGenInputs['ProfileDetailsInput'] | null; // ProfileDetailsInput } - updateUserWalletKeys: { // args - data?: NexusGenInputs['UserKeyInputType'][] | null; // [UserKeyInputType!] + updateUserPreferences: { // args + userKeys?: NexusGenInputs['UserKeyInputType'][] | null; // [UserKeyInputType!] } vote: { // args amount_in_sat: number; // Int! @@ -753,13 +838,16 @@ export interface NexusGenArgTypes { export interface NexusGenAbstractTypeMembers { Post: "Bounty" | "Question" | "Story" + BaseUser: "MyProfile" | "User" PostBase: "Bounty" | "Question" | "Story" } export interface NexusGenTypeInterfaces { Bounty: "PostBase" + MyProfile: "BaseUser" Question: "PostBase" Story: "PostBase" + User: "BaseUser" } export type NexusGenObjectNames = keyof NexusGenObjects; @@ -776,7 +864,7 @@ export type NexusGenUnionNames = keyof NexusGenUnions; export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never; -export type NexusGenAbstractsUsingStrategyResolveType = "Post" | "PostBase"; +export type NexusGenAbstractsUsingStrategyResolveType = "BaseUser" | "Post" | "PostBase"; export type NexusGenFeaturesConfig = { abstractTypeStrategies: { diff --git a/api/functions/graphql/schema.graphql b/api/functions/graphql/schema.graphql index e199a9e..172990d 100644 --- a/api/functions/graphql/schema.graphql +++ b/api/functions/graphql/schema.graphql @@ -18,6 +18,24 @@ type Award { url: String! } +interface BaseUser { + avatar: String! + bio: String + email: String + github: String + id: Int! + jobTitle: String + join_date: Date! + lightning_address: String + linkedin: String + location: String + name: String! + role: String + stories: [Story!]! + twitter: String + website: String +} + type Bounty implements PostBase { applicants_count: Int! applications: [BountyApplication!]! @@ -99,11 +117,32 @@ type Mutation { createStory(data: StoryInputType): Story deleteStory(id: Int!): Story donate(amount_in_sat: Int!): Donation! - updateProfile(data: UpdateProfileInput): User - updateUserWalletKeys(data: [UserKeyInputType!]): [UserKey!]! + updateProfileDetails(data: ProfileDetailsInput): MyProfile + updateUserPreferences(userKeys: [UserKeyInputType!]): [MyProfile!]! vote(amount_in_sat: Int!, item_id: Int!, item_type: VOTE_ITEM_TYPE!): Vote! } +type MyProfile implements BaseUser { + avatar: String! + bio: String + email: String + github: String + id: Int! + jobTitle: String + join_date: Date! + lightning_address: String + linkedin: String + location: String + name: String! + nostr_prv_key: String + nostr_pub_key: String + role: String + stories: [Story!]! + twitter: String + walletsKeys: [WalletKey!]! + website: String +} + enum POST_TYPE { Bounty Question @@ -132,6 +171,20 @@ type PostComment { votes_count: Int! } +input ProfileDetailsInput { + avatar: String + bio: String + email: String + github: String + jobTitle: String + lightning_address: String + linkedin: String + location: String + name: String + twitter: String + website: String +} + type Project { awards: [Award!]! category: Category! @@ -161,8 +214,7 @@ type Query { getProject(id: Int!): Project! getTrendingPosts: [Post!]! hottestProjects(skip: Int = 0, take: Int = 50): [Project!]! - me: User - myWalletsKeys: [UserKey!]! + me: MyProfile newProjects(skip: Int = 0, take: Int = 50): [Project!]! officialTags: [Tag!]! popularTags: [Tag!]! @@ -219,21 +271,7 @@ type Tag { title: String! } -input UpdateProfileInput { - avatar: String - bio: String - email: String - github: String - jobTitle: String - lightning_address: String - linkedin: String - location: String - name: String - twitter: String - website: String -} - -type User { +type User implements BaseUser { avatar: String! bio: String email: String @@ -245,19 +283,12 @@ type User { linkedin: String location: String name: String! - nostr_prv_key: String - nostr_pub_key: String role: String stories: [Story!]! twitter: String website: String } -type UserKey { - key: String! - name: String! -} - input UserKeyInputType { key: String! name: String! @@ -280,4 +311,9 @@ type Vote { paid: Boolean! payment_hash: String! payment_request: String! +} + +type WalletKey { + key: String! + name: String! } \ No newline at end of file diff --git a/api/functions/graphql/types/users.js b/api/functions/graphql/types/users.js index e04dd1f..f5f5a99 100644 --- a/api/functions/graphql/types/users.js +++ b/api/functions/graphql/types/users.js @@ -1,13 +1,14 @@ const { prisma } = require('../../../prisma'); -const { objectType, extendType, intArg, nonNull, inputObjectType, list } = require("nexus"); +const { objectType, extendType, intArg, nonNull, inputObjectType, interfaceType, list } = require("nexus"); const { getUserByPubKey } = require("../../../auth/utils/helperFuncs"); const { removeNulls } = require("./helpers"); -const User = objectType({ - name: 'User', + +const BaseUser = interfaceType({ + name: 'BaseUser', definition(t) { t.nonNull.int('id'); t.nonNull.string('name'); @@ -23,8 +24,7 @@ const User = objectType({ t.string('linkedin') t.string('bio') t.string('location') - t.string('nostr_prv_key') - t.string('nostr_pub_key') + t.nonNull.list.nonNull.field('stories', { type: "Story", @@ -32,6 +32,34 @@ const User = objectType({ return prisma.story.findMany({ where: { user_id: parent.id, is_published: true }, orderBy: { createdAt: "desc" } }); } }); + + + }, + resolveType() { + return null + }, +}) + +const User = objectType({ + name: 'User', + definition(t) { + t.implements('BaseUser') + } +}) + +const MyProfile = objectType({ + name: 'MyProfile', + definition(t) { + t.implements('BaseUser') + t.string('nostr_prv_key') + t.string('nostr_pub_key') + + t.nonNull.list.nonNull.field('walletsKeys', { + type: "WalletKey", + resolve: (parent) => { + return prisma.user.findUnique({ where: { id: parent.id } }).userKeys(); + } + }); } }) @@ -40,7 +68,7 @@ const me = extendType({ type: "Query", definition(t) { t.field('me', { - type: "User", + type: "MyProfile", async resolve(parent, args, context) { const user = await getUserByPubKey(context.userPubKey) return user @@ -58,21 +86,14 @@ const profile = extendType({ id: nonNull(intArg()) }, async resolve(parent, { id }, ctx) { - const user = await getUserByPubKey(ctx.userPubKey); - const isSelf = user?.id === id; - const profile = await prisma.user.findFirst({ - where: { id }, - }); - if (!isSelf) - profile.nostr_prv_key = null; - return profile; + return prisma.user.findUnique({ where: { id } }) } }) } }) -const UpdateProfileInput = inputObjectType({ - name: 'UpdateProfileInput', +const ProfileDetailsInput = inputObjectType({ + name: 'ProfileDetailsInput', definition(t) { t.string('name'); t.string('avatar'); @@ -88,12 +109,12 @@ const UpdateProfileInput = inputObjectType({ } }) -const updateProfile = extendType({ +const updateProfileDetails = extendType({ type: 'Mutation', definition(t) { - t.field('updateProfile', { - type: 'User', - args: { data: UpdateProfileInput }, + t.field('updateProfileDetails', { + type: 'MyProfile', + args: { data: ProfileDetailsInput }, async resolve(_root, args, ctx) { const user = await getUserByPubKey(ctx.userPubKey); @@ -117,35 +138,15 @@ const updateProfile = extendType({ }) -const UserKey = objectType({ - name: 'UserKey', +const WalletKey = objectType({ + name: 'WalletKey', definition(t) { t.nonNull.string('key'); t.nonNull.string('name'); } }) -const myWalletsKeys = extendType({ - type: "Query", - definition(t) { - t.nonNull.list.nonNull.field('myWalletsKeys', { - type: "UserKey", - async resolve(_, __, ctx) { - const user = await getUserByPubKey(ctx.userPubKey); - - if (!user) - throw new Error("You have to login"); - - return prisma.userKey.findMany({ - where: { - user_id: user.id, - } - }) - } - }) - } -}) const UserKeyInputType = inputObjectType({ name: 'UserKeyInputType', @@ -157,21 +158,21 @@ const UserKeyInputType = inputObjectType({ -const updateUserWalletKeys = extendType({ +const updateUserPreferences = extendType({ type: 'Mutation', definition(t) { - t.nonNull.list.nonNull.field('updateUserWalletKeys', { - type: 'UserKey', - args: { data: list(nonNull(UserKeyInputType)) }, + t.nonNull.list.nonNull.field('updateUserPreferences', { + type: 'MyProfile', + args: { userKeys: list(nonNull(UserKeyInputType)) }, async resolve(_root, args, ctx) { - - const user = await getUserByPubKey(ctx.userPubKey); if (!user) throw new Error("You have to login"); + //Update the userkeys + //-------------------- // Check if all the sent keys belong to the user const userKeys = (await prisma.userKey.findMany({ @@ -215,8 +216,7 @@ const updateUserWalletKeys = extendType({ })) }) - return newKeys; - + return prisma.user.findUnique({ where: { id: user.id } }); } }) } @@ -224,16 +224,17 @@ const updateUserWalletKeys = extendType({ + module.exports = { // Types + BaseUser, User, - UpdateProfileInput, - UserKey, + MyProfile, + WalletKey, // Queries me, profile, - myWalletsKeys, // Mutations - updateProfile, - updateUserWalletKeys, + updateProfileDetails, + updateUserPreferences, } \ No newline at end of file diff --git a/src/features/Auth/pages/me.graphql b/src/features/Auth/pages/me.graphql index 990c33f..8153621 100644 --- a/src/features/Auth/pages/me.graphql +++ b/src/features/Auth/pages/me.graphql @@ -4,5 +4,7 @@ query Me { name avatar join_date + jobTitle + bio } } diff --git a/src/features/Profiles/pages/EditProfilePage/AccountCard/AccountCard.tsx b/src/features/Profiles/pages/EditProfilePage/AccountCard/AccountCard.tsx deleted file mode 100644 index 854fbe8..0000000 --- a/src/features/Profiles/pages/EditProfilePage/AccountCard/AccountCard.tsx +++ /dev/null @@ -1,190 +0,0 @@ -import Button from 'src/Components/Button/Button'; -import { useAppDispatch } from 'src/utils/hooks'; -import { openModal } from 'src/redux/features/modals.slice'; -import Card from 'src/Components/Card/Card'; -import { useMyWalletsKeysQuery, useUpdateUserWalletsKeysMutation } from 'src/graphql'; -import Skeleton from 'react-loading-skeleton'; -import { useReducer } from 'react'; - - -interface Props { - -} - - -type State = { - hasNewChanges: boolean, - keys: Array<{ key: string, name: string }>, - oldKeys: Array<{ key: string, name: string }> -} - - -type Action = - | { - type: 'set' - payload: State['keys'] - } - | { - type: 'delete', - payload: { idx: number } - } - | { - type: 'update', - payload: { - idx: number, - value: string, - } - } - | { - type: 'cancel' - } - -function reducer(state: State, action: Action): State { - switch (action.type) { - case 'set': - return { - hasNewChanges: false, - keys: [...action.payload], - oldKeys: [...action.payload], - } - case 'delete': - if (state.keys.length === 1) - return state; - return { - hasNewChanges: true, - oldKeys: state.oldKeys, - keys: [...state.keys.slice(0, action.payload.idx), ...state.keys.slice(action.payload.idx + 1)] - }; - case 'update': - return { - hasNewChanges: true, - oldKeys: state.oldKeys, - keys: state.keys.map((item, idx) => { - if (idx === action.payload.idx) - return { - ...item, - name: action.payload.value - } - return item; - }), - - } - case 'cancel': - return { - hasNewChanges: false, - keys: [...state.oldKeys], - oldKeys: state.oldKeys, - } - } -} - -export default function AccountCard({ }: Props) { - - const dispatch = useAppDispatch(); - const [keysState, keysDispatch] = useReducer(reducer, { keys: [], oldKeys: [], hasNewChanges: false, }); - const myKeysQuery = useMyWalletsKeysQuery({ - onCompleted: data => { - keysDispatch({ - type: 'set', - payload: data.myWalletsKeys - }) - } - }); - const [updateKeys, updatingKeysStatus] = useUpdateUserWalletsKeysMutation({ - onCompleted: data => { - keysDispatch({ - type: "set", - payload: data.updateUserWalletKeys - }) - } - }) - - const connectNewWallet = () => { - dispatch(openModal({ Modal: "LinkingAccountModal" })) - } - - const saveChanges = () => { - updateKeys({ - variables: { - data: keysState.keys.map(v => ({ key: v.key, name: v.name })) - } - }) - } - - const cancelChanges = () => { - keysDispatch({ type: 'cancel' }); - } - - - return ( - -

🔒 Linking Accounts

-
-

Linked Wallets

-

- These are the wallets that you can login to this account from. -
- You can add a new wallet from the button below. -

- { - myKeysQuery.loading ? - - : - <> - -
- - -
- {keysState.keys.length < 3 && } - - } -
-
- ) -} diff --git a/src/features/Profiles/pages/EditProfilePage/AccountCard/LinkingAccountModal/myWalletsKeys.graphql b/src/features/Profiles/pages/EditProfilePage/AccountCard/LinkingAccountModal/myWalletsKeys.graphql deleted file mode 100644 index c5bd961..0000000 --- a/src/features/Profiles/pages/EditProfilePage/AccountCard/LinkingAccountModal/myWalletsKeys.graphql +++ /dev/null @@ -1,13 +0,0 @@ -query MyWalletsKeys { - myWalletsKeys { - key - name - } -} - -mutation UpdateUserWalletsKeys($data: [UserKeyInputType!]) { - updateUserWalletKeys(data: $data) { - key - name - } -} diff --git a/src/features/Profiles/pages/EditProfilePage/EditProfilePage.tsx b/src/features/Profiles/pages/EditProfilePage/EditProfilePage.tsx index ac3939c..6a9a6a0 100644 --- a/src/features/Profiles/pages/EditProfilePage/EditProfilePage.tsx +++ b/src/features/Profiles/pages/EditProfilePage/EditProfilePage.tsx @@ -7,7 +7,6 @@ import { useAppSelector, useMediaQuery } from "src/utils/hooks"; import UpdateMyProfileTab from "./UpdateMyProfileTab/UpdateMyProfileTab"; import { Helmet } from 'react-helmet' import { MEDIA_QUERIES } from "src/utils/theme"; -import AccountCard from "./AccountCard/AccountCard"; import PreferencesTab from "./PreferencesTab/PreferencesTab"; import Card from "src/Components/Card/Card"; @@ -18,11 +17,7 @@ const links = [ path: 'my-profile', }, { - text: "🙍‍♂️ Account", - path: 'account', - }, - { - text: "⚙️ Preferences", + text: "⚙️ Settings & Preferences", path: 'preferences', } ] @@ -30,24 +25,10 @@ const links = [ export default function EditProfilePage() { - const userId = useAppSelector(state => state.user.me?.id) - const profileQuery = useProfileQuery({ - variables: { - profileId: userId!, - }, - skip: !userId, - }) - const isMediumScreen = useMediaQuery(MEDIA_QUERIES.isMedium) + const isMediumScreen = useMediaQuery(MEDIA_QUERIES.isMedium); - - if (!userId || profileQuery.loading) - return - - if (!profileQuery.data?.profile) - return - return ( <> @@ -97,9 +78,8 @@ export default function EditProfilePage() {
} /> - } /> - } /> - + } /> + } />
diff --git a/src/features/Profiles/pages/EditProfilePage/AccountCard/AccountCard.stories.tsx b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkedAccountsCard/LinkedAccountsCard.stories.tsx similarity index 90% rename from src/features/Profiles/pages/EditProfilePage/AccountCard/AccountCard.stories.tsx rename to src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkedAccountsCard/LinkedAccountsCard.stories.tsx index 7463ed6..319570a 100644 --- a/src/features/Profiles/pages/EditProfilePage/AccountCard/AccountCard.stories.tsx +++ b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkedAccountsCard/LinkedAccountsCard.stories.tsx @@ -1,5 +1,5 @@ import { ComponentStory, ComponentMeta } from '@storybook/react'; -import AccountCard from './AccountCard'; +import AccountCard from './LinkedAccountsCard'; export default { title: 'Profiles/Profile Page/Account Card', diff --git a/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkedAccountsCard/LinkedAccountsCard.tsx b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkedAccountsCard/LinkedAccountsCard.tsx new file mode 100644 index 0000000..0526825 --- /dev/null +++ b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkedAccountsCard/LinkedAccountsCard.tsx @@ -0,0 +1,168 @@ +import Button from 'src/Components/Button/Button'; +import { useAppDispatch } from 'src/utils/hooks'; +import { openModal } from 'src/redux/features/modals.slice'; +import Card from 'src/Components/Card/Card'; +import { MyProfile } from 'src/graphql'; +import Skeleton from 'react-loading-skeleton'; +import { useReducer } from 'react'; + + +interface Props { + walletsKeys: MyProfile['walletsKeys'] +} + + +type State = { + hasNewChanges: boolean, + keys: Array<{ key: string, name: string }>, + oldKeys: Array<{ key: string, name: string }> +} + + +type Action = + | { + type: 'set' + payload: State['keys'] + } + | { + type: 'delete', + payload: { idx: number } + } + | { + type: 'update', + payload: { + idx: number, + value: string, + } + } + | { + type: 'cancel' + } + +function reducer(state: State, action: Action): State { + switch (action.type) { + case 'set': + return { + hasNewChanges: false, + keys: [...action.payload], + oldKeys: [...action.payload], + } + case 'delete': + if (state.keys.length === 1) + return state; + return { + hasNewChanges: true, + oldKeys: state.oldKeys, + keys: [...state.keys.slice(0, action.payload.idx), ...state.keys.slice(action.payload.idx + 1)] + }; + case 'update': + return { + hasNewChanges: true, + oldKeys: state.oldKeys, + keys: state.keys.map((item, idx) => { + if (idx === action.payload.idx) + return { + ...item, + name: action.payload.value + } + return item; + }), + + } + case 'cancel': + return { + hasNewChanges: false, + keys: [...state.oldKeys], + oldKeys: state.oldKeys, + } + } +} + +export default function LinkedAccountsCard({ walletsKeys }: Props) { + + const dispatch = useAppDispatch(); + const [keysState, keysDispatch] = useReducer(reducer, { keys: [], oldKeys: [], hasNewChanges: false, }); + + // const [updateKeys, updatingKeysStatus] = useUpdateUserWalletsKeysMutation({ + // onCompleted: data => { + // keysDispatch({ + // type: "set", + // payload: data.updateUserWalletKeys + // }) + // } + // }) + + const connectNewWallet = () => { + dispatch(openModal({ Modal: "LinkingAccountModal" })) + } + + const saveChanges = () => { + // updateKeys({ + // variables: { + // data: keysState.keys.map(v => ({ key: v.key, name: v.name })) + // } + // }) + } + + const cancelChanges = () => { + keysDispatch({ type: 'cancel' }); + } + + + return ( + +

🔐 Linked Accounts

+

+ These are the wallets that you can login to this account from. You can add a new wallet below. +

+
+
    + {walletsKeys.map((item, idx) => +
  • + { + keysDispatch({ + type: 'update', + payload: { + idx, + value: e.target.value + } + }) + }} + className='p-0 border-0 focus:border-0 focus:outline-none grow + focus:ring-0 placeholder:!text-gray-400' /> + + {walletsKeys.length > 1 && } +
  • + )} +
+ {/*
+ + +
*/} + {walletsKeys.length < 3 && + } + +
+
+ ) +} diff --git a/src/features/Profiles/pages/EditProfilePage/AccountCard/LinkingAccountModal/LinkingAccountModal.tsx b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkingAccountModal/LinkingAccountModal.tsx similarity index 100% rename from src/features/Profiles/pages/EditProfilePage/AccountCard/LinkingAccountModal/LinkingAccountModal.tsx rename to src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkingAccountModal/LinkingAccountModal.tsx diff --git a/src/features/Profiles/pages/EditProfilePage/AccountCard/LinkingAccountModal/index.ts b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkingAccountModal/index.ts similarity index 100% rename from src/features/Profiles/pages/EditProfilePage/AccountCard/LinkingAccountModal/index.ts rename to src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkingAccountModal/index.ts diff --git a/src/features/Profiles/pages/EditProfilePage/PreferencesTab/PreferencesTab.tsx b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/PreferencesTab.tsx index 2711363..2fb17e8 100644 --- a/src/features/Profiles/pages/EditProfilePage/PreferencesTab/PreferencesTab.tsx +++ b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/PreferencesTab.tsx @@ -1,20 +1,31 @@ -import { Nullable } from 'remirror'; +import LinkedAccountsCard from './LinkedAccountsCard/LinkedAccountsCard'; import CommentsSettingsCard from './CommentsSettingsCard/CommentsSettingsCard'; +import { useMyProfilePreferencesQuery, useUpdateUserPreferencesMutation } from 'src/graphql'; +import LoadingPage from 'src/Components/LoadingPage/LoadingPage'; +import NotFoundPage from "src/features/Shared/pages/NotFoundPage/NotFoundPage"; interface Props { - isOwner?: boolean; - nostr_pub_key: Nullable; - nostr_prv_key: Nullable; - } -export default function PreferencesTab({ nostr_prv_key, nostr_pub_key, isOwner }: Props) { + + +export default function PreferencesTab() { + + const query = useMyProfilePreferencesQuery(); + const [mutate, mutationStatus] = useUpdateUserPreferencesMutation(); + + if (query.loading) + return + + if (!query.data?.me) + return return (
-
- +
+ +
) diff --git a/src/features/Profiles/pages/EditProfilePage/PreferencesTab/profilePreferences.graphql b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/profilePreferences.graphql new file mode 100644 index 0000000..d30db02 --- /dev/null +++ b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/profilePreferences.graphql @@ -0,0 +1,21 @@ +query MyProfilePreferences { + me { + walletsKeys { + key + name + } + nostr_prv_key + nostr_pub_key + } +} + +mutation UpdateUserPreferences($userKeys: [UserKeyInputType!]) { + updateUserPreferences(userKeys: $userKeys) { + walletsKeys { + key + name + } + nostr_pub_key + nostr_prv_key + } +} diff --git a/src/features/Profiles/pages/EditProfilePage/SaveChangesCard/SaveChangesCard.tsx b/src/features/Profiles/pages/EditProfilePage/SaveChangesCard/SaveChangesCard.tsx index 3f616c7..0011cd5 100644 --- a/src/features/Profiles/pages/EditProfilePage/SaveChangesCard/SaveChangesCard.tsx +++ b/src/features/Profiles/pages/EditProfilePage/SaveChangesCard/SaveChangesCard.tsx @@ -17,14 +17,10 @@ interface Props { export default function SaveChangesCard(props: Props) { - const userId = useAppSelector(state => state.user.me?.id!) - const profileQuery = useProfileQuery({ - variables: { - profileId: userId, - }, - }) + const user = useAppSelector(state => state.user.me) - if (!profileQuery.data?.profile) + + if (!user) return <> @@ -38,18 +34,18 @@ export default function SaveChangesCard(props: Props) {
- + to={createRoute({ type: 'profile', id: user.id, username: user.name })}> +
-

{profileQuery.data.profile ? trimText(profileQuery.data.profile.name, 30) : "Anonymouse"}

- {profileQuery.data.profile.jobTitle &&

{profileQuery.data.profile.jobTitle}

} +

{user ? trimText(user.name, 30) : "Anonymouse"}

+ {user.jobTitle &&

{user.jobTitle}

}
{/* {showTimeAgo &&

{dayjs().diff(props.date, 'hour') < 24 ? `${dayjs().diff(props.date, 'hour')}h ago` : undefined}

} */}
-

{trimText(profileQuery.data.profile.bio, 120)}

+

{trimText(user.bio, 120)}