feat: update the structure of the profile and edit-profile apis

This commit is contained in:
MTG2000
2022-08-17 12:36:33 +03:00
parent 2085529243
commit 5a7bac8325
23 changed files with 730 additions and 504 deletions

View File

@@ -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: {

View File

@@ -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!
}

View File

@@ -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,
}

View File

@@ -4,5 +4,7 @@ query Me {
name
avatar
join_date
jobTitle
bio
}
}

View File

@@ -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 (
<Card>
<p className="text-body2 font-bold">🔒 Linking Accounts</p>
<div className='mt-24 flex flex-col gap-16'>
<p className="text-body3 font-bold">Linked Wallets</p>
<p className="text-body4 text-gray-600">
These are the wallets that you can login to this account from.
<br />
You can add a new wallet from the button below.
</p>
{
myKeysQuery.loading ?
<ul className="mt-8 relative flex flex-col gap-8">
{Array(2).fill(0).map((_, idx) =>
<li key={idx} className="text-body4 border-b py-12 px-16 border border-gray-200 rounded-16">
<Skeleton width='15ch' />
</li>
)}
</ul>
:
<>
<ul className="mt-8 relative flex flex-col gap-8">
{keysState.keys.map((item, idx) =>
<li key={item.key} className="flex justify-between items-center text-body4 border-b py-12 px-16 border border-gray-200 rounded-16">
<input
type="text"
value={item.name}
onChange={e => {
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' />
<Button size='sm' color='none' className='text-red-500 !p-0' onClick={() => keysDispatch({ type: 'delete', payload: { idx } })}>Delete key</Button>
</li>
)}
</ul>
<div className="flex justify-end gap-8">
<Button
color='gray'
className=''
disabled={!keysState.hasNewChanges || updatingKeysStatus.loading}
onClick={cancelChanges}
>
Cancel
</Button>
<Button
color='black'
className=''
disabled={!keysState.hasNewChanges}
isLoading={updatingKeysStatus.loading}
onClick={saveChanges}
>
Save Changes
</Button>
</div>
{keysState.keys.length < 3 && <Button color='primary' className='mt-16' onClick={connectNewWallet}>
Connect new wallet
</Button>}
</>
}
</div>
</Card>
)
}

View File

@@ -1,13 +0,0 @@
query MyWalletsKeys {
myWalletsKeys {
key
name
}
}
mutation UpdateUserWalletsKeys($data: [UserKeyInputType!]) {
updateUserWalletKeys(data: $data) {
key
name
}
}

View File

@@ -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 <LoadingPage />
if (!profileQuery.data?.profile)
return <NotFoundPage />
return (
<>
<Helmet>
@@ -97,9 +78,8 @@ export default function EditProfilePage() {
<main className="md:col-span-3">
<Routes>
<Route index element={<Navigate to='my-profile' />} />
<Route path='my-profile' element={<UpdateMyProfileTab data={profileQuery.data.profile} />} />
<Route path='account' element={<AccountCard />} />
<Route path='preferences' element={<PreferencesTab nostr_prv_key={profileQuery.data.profile.nostr_prv_key} nostr_pub_key={profileQuery.data.profile.nostr_pub_key} isOwner={true} />
<Route path='my-profile' element={<UpdateMyProfileTab />} />
<Route path='preferences' element={<PreferencesTab />
} />
</Routes>
</main>

View File

@@ -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',

View File

@@ -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 (
<Card>
<p className="text-body2 font-bold">🔐 Linked Accounts</p>
<p className="text-body4 text-gray-600 mt-8">
These are the wallets that you can login to this account from. You can add a new wallet below.
</p>
<div className='mt-24 flex flex-col gap-16'>
<ul className="mt-8 relative flex flex-col gap-8">
{walletsKeys.map((item, idx) =>
<li key={item.key} className="flex justify-between items-center text-body4 border-b py-12 px-16 border border-gray-200 rounded-16">
<input
type="text"
value={item.name}
onChange={e => {
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 && <Button size='sm' color='none' className='text-red-500 !p-0' onClick={() => keysDispatch({ type: 'delete', payload: { idx } })}>Delete key</Button>}
</li>
)}
</ul>
{/* <div className="flex justify-end gap-8">
<Button
color='gray'
className=''
disabled={!keysState.hasNewChanges || updatingKeysStatus.loading}
onClick={cancelChanges}
>
Cancel
</Button>
<Button
color='black'
className=''
disabled={!keysState.hasNewChanges}
isLoading={updatingKeysStatus.loading}
onClick={saveChanges}
>
Save Changes
</Button>
</div> */}
{walletsKeys.length < 3 &&
<Button color='white' className='mt-16' onClick={connectNewWallet}>
Connect new wallet
</Button>}
</div>
</Card>
)
}

View File

@@ -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<string>;
nostr_prv_key: Nullable<string>;
}
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 <LoadingPage />
if (!query.data?.me)
return <NotFoundPage />
return (
<div className="grid grid-cols-1 md:grid-cols-3 gap-24">
<div className="col-span-2">
<CommentsSettingsCard nostr_prv_key={nostr_prv_key} nostr_pub_key={nostr_pub_key} />
<div className="col-span-2 flex flex-col gap-24">
<LinkedAccountsCard walletsKeys={query.data.me.walletsKeys} />
<CommentsSettingsCard nostr_prv_key={query.data.me.nostr_prv_key} nostr_pub_key={query.data.me.nostr_pub_key} />
</div>
</div>
)

View File

@@ -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
}
}

View File

@@ -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) {
<div className='hidden md:flex gap-8'>
<Link
className='shrink-0'
to={createRoute({ type: 'profile', id: profileQuery.data.profile.id, username: profileQuery.data.profile.name })}>
<Avatar width={48} src={profileQuery.data.profile.avatar!} />
to={createRoute({ type: 'profile', id: user.id, username: user.name })}>
<Avatar width={48} src={user.avatar!} />
</Link>
<div className='overflow-hidden'>
<p className={`text-body4 text-black font-medium overflow-hidden text-ellipsis`}>{profileQuery.data.profile ? trimText(profileQuery.data.profile.name, 30) : "Anonymouse"}</p>
{profileQuery.data.profile.jobTitle && <p className={`text-body6 text-gray-600`}>{profileQuery.data.profile.jobTitle}</p>}
<p className={`text-body4 text-black font-medium overflow-hidden text-ellipsis`}>{user ? trimText(user.name, 30) : "Anonymouse"}</p>
{user.jobTitle && <p className={`text-body6 text-gray-600`}>{user.jobTitle}</p>}
</div>
{/* {showTimeAgo && <p className={`${nameSize[size]} text-gray-500 ml-auto `}>
{dayjs().diff(props.date, 'hour') < 24 ? `${dayjs().diff(props.date, 'hour')}h ago` : undefined}
</p>} */}
</div>
<p className="hidden md:block text-body5">{trimText(profileQuery.data.profile.bio, 120)}</p>
<p className="hidden md:block text-body5">{trimText(user.bio, 120)}</p>
<div className="flex flex-col gap-16">
<Button
color="primary"

View File

@@ -1,33 +1,22 @@
import { SubmitHandler, useForm } from "react-hook-form"
import Button from "src/Components/Button/Button";
import { User, useUpdateProfileAboutMutation } from "src/graphql";
import { User, useUpdateProfileAboutMutation, useMyProfileAboutQuery, UpdateProfileAboutMutationVariables } from "src/graphql";
import { NotificationsService } from "src/services/notifications.service";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import Avatar from "src/features/Profiles/Components/Avatar/Avatar";
import { usePrompt } from "src/utils/hooks";
import { useAppDispatch, usePrompt } from "src/utils/hooks";
import SaveChangesCard from "../SaveChangesCard/SaveChangesCard";
import { toast } from "react-toastify";
import Card from "src/Components/Card/Card";
import LoadingPage from "src/Components/LoadingPage/LoadingPage";
import NotFoundPage from "src/features/Shared/pages/NotFoundPage/NotFoundPage";
import { setUser } from "src/redux/features/user.slice";
interface Props {
data: Pick<User,
| 'name'
| 'email'
| 'lightning_address'
| 'jobTitle'
| 'avatar'
| 'website'
| 'github'
| 'twitter'
| 'linkedin'
| 'location'
| 'bio'
>,
onClose?: () => void;
}
type IFormInputs = Props['data'];
type IFormInputs = NonNullable<UpdateProfileAboutMutationVariables['data']>;
const schema: yup.SchemaOf<IFormInputs> = yup.object({
name: yup.string().trim().required().min(2),
@@ -63,21 +52,35 @@ const schema: yup.SchemaOf<IFormInputs> = yup.object({
}).required();
export default function UpdateMyProfileTab({ data, onClose }: Props) {
export default function UpdateMyProfileTab() {
const { register, formState: { errors, isDirty, }, handleSubmit, reset } = useForm<IFormInputs>({
defaultValues: data,
defaultValues: {},
resolver: yupResolver(schema),
mode: 'onBlur',
});
const profileQuery = useMyProfileAboutQuery({
onCompleted: data => {
if (data.me)
reset(data.me)
}
})
const [mutate, mutationStatus] = useUpdateProfileAboutMutation();
const dispatch = useAppDispatch()
usePrompt('You may have some unsaved changes. You still want to leave?', isDirty)
if (profileQuery.loading)
return <LoadingPage />
if (!profileQuery.data?.me)
return <NotFoundPage />
const onSubmit: SubmitHandler<IFormInputs> = data => {
const toastId = toast.loading("Saving changes...", NotificationsService.defaultOptions)
@@ -98,9 +101,12 @@ export default function UpdateMyProfileTab({ data, onClose }: Props) {
website: data.website,
}
},
onCompleted: () => {
reset(data);
toast.update(toastId, { render: "Saved changes successfully", type: "success", ...NotificationsService.defaultOptions, isLoading: false });
onCompleted: ({ updateProfileDetails: data }) => {
if (data) {
dispatch(setUser(data))
reset(data);
toast.update(toastId, { render: "Saved changes successfully", type: "success", ...NotificationsService.defaultOptions, isLoading: false });
}
}
})
.catch(() => {
@@ -114,7 +120,7 @@ export default function UpdateMyProfileTab({ data, onClose }: Props) {
<Card className="md:col-span-2" defaultPadding={false}>
<div className="bg-gray-600 relative h-[160px] rounded-t-16">
<div className="absolute left-24 bottom-0 translate-y-1/2">
<Avatar src={data.avatar} width={120} />
<Avatar src={profileQuery.data.me.avatar} width={120} />
</div>
</div>
<div className="p-16 md:p-24 mt-64">

View File

@@ -0,0 +1,37 @@
query MyProfileAbout {
me {
id
name
avatar
join_date
role
email
jobTitle
lightning_address
website
twitter
github
linkedin
bio
location
}
}
mutation updateProfileAbout($data: ProfileDetailsInput) {
updateProfileDetails(data: $data) {
id
name
avatar
join_date
role
email
jobTitle
lightning_address
website
twitter
github
linkedin
bio
location
}
}

View File

@@ -1,18 +0,0 @@
mutation updateProfileAbout($data: UpdateProfileInput) {
updateProfile(data: $data) {
id
name
avatar
join_date
website
role
email
lightning_address
jobTitle
twitter
github
linkedin
bio
location
}
}

View File

@@ -24,7 +24,5 @@ query profile($profileId: Int!) {
icon
}
}
nostr_prv_key
nostr_pub_key
}
}

View File

@@ -35,6 +35,24 @@ export type Award = {
url: Scalars['String'];
};
export type BaseUser = {
avatar: Scalars['String'];
bio: Maybe<Scalars['String']>;
email: Maybe<Scalars['String']>;
github: Maybe<Scalars['String']>;
id: Scalars['Int'];
jobTitle: Maybe<Scalars['String']>;
join_date: Scalars['Date'];
lightning_address: Maybe<Scalars['String']>;
linkedin: Maybe<Scalars['String']>;
location: Maybe<Scalars['String']>;
name: Scalars['String'];
role: Maybe<Scalars['String']>;
stories: Array<Story>;
twitter: Maybe<Scalars['String']>;
website: Maybe<Scalars['String']>;
};
export type Bounty = PostBase & {
__typename?: 'Bounty';
applicants_count: Scalars['Int'];
@@ -121,8 +139,8 @@ export type Mutation = {
createStory: Maybe<Story>;
deleteStory: Maybe<Story>;
donate: Donation;
updateProfile: Maybe<User>;
updateUserWalletKeys: Array<UserKey>;
updateProfileDetails: Maybe<MyProfile>;
updateUserPreferences: Array<MyProfile>;
vote: Vote;
};
@@ -154,13 +172,13 @@ export type MutationDonateArgs = {
};
export type MutationUpdateProfileArgs = {
data: InputMaybe<UpdateProfileInput>;
export type MutationUpdateProfileDetailsArgs = {
data: InputMaybe<ProfileDetailsInput>;
};
export type MutationUpdateUserWalletKeysArgs = {
data: InputMaybe<Array<UserKeyInputType>>;
export type MutationUpdateUserPreferencesArgs = {
userKeys: InputMaybe<Array<UserKeyInputType>>;
};
@@ -170,6 +188,28 @@ export type MutationVoteArgs = {
item_type: Vote_Item_Type;
};
export type MyProfile = BaseUser & {
__typename?: 'MyProfile';
avatar: Scalars['String'];
bio: Maybe<Scalars['String']>;
email: Maybe<Scalars['String']>;
github: Maybe<Scalars['String']>;
id: Scalars['Int'];
jobTitle: Maybe<Scalars['String']>;
join_date: Scalars['Date'];
lightning_address: Maybe<Scalars['String']>;
linkedin: Maybe<Scalars['String']>;
location: Maybe<Scalars['String']>;
name: Scalars['String'];
nostr_prv_key: Maybe<Scalars['String']>;
nostr_pub_key: Maybe<Scalars['String']>;
role: Maybe<Scalars['String']>;
stories: Array<Story>;
twitter: Maybe<Scalars['String']>;
walletsKeys: Array<WalletKey>;
website: Maybe<Scalars['String']>;
};
export enum Post_Type {
Bounty = 'Bounty',
Question = 'Question',
@@ -199,6 +239,20 @@ export type PostComment = {
votes_count: Scalars['Int'];
};
export type ProfileDetailsInput = {
avatar: InputMaybe<Scalars['String']>;
bio: InputMaybe<Scalars['String']>;
email: InputMaybe<Scalars['String']>;
github: InputMaybe<Scalars['String']>;
jobTitle: InputMaybe<Scalars['String']>;
lightning_address: InputMaybe<Scalars['String']>;
linkedin: InputMaybe<Scalars['String']>;
location: InputMaybe<Scalars['String']>;
name: InputMaybe<Scalars['String']>;
twitter: InputMaybe<Scalars['String']>;
website: InputMaybe<Scalars['String']>;
};
export type Project = {
__typename?: 'Project';
awards: Array<Award>;
@@ -230,8 +284,7 @@ export type Query = {
getProject: Project;
getTrendingPosts: Array<Post>;
hottestProjects: Array<Project>;
me: Maybe<User>;
myWalletsKeys: Array<UserKey>;
me: Maybe<MyProfile>;
newProjects: Array<Project>;
officialTags: Array<Tag>;
popularTags: Array<Tag>;
@@ -368,21 +421,7 @@ export type Tag = {
title: Scalars['String'];
};
export type UpdateProfileInput = {
avatar: InputMaybe<Scalars['String']>;
bio: InputMaybe<Scalars['String']>;
email: InputMaybe<Scalars['String']>;
github: InputMaybe<Scalars['String']>;
jobTitle: InputMaybe<Scalars['String']>;
lightning_address: InputMaybe<Scalars['String']>;
linkedin: InputMaybe<Scalars['String']>;
location: InputMaybe<Scalars['String']>;
name: InputMaybe<Scalars['String']>;
twitter: InputMaybe<Scalars['String']>;
website: InputMaybe<Scalars['String']>;
};
export type User = {
export type User = BaseUser & {
__typename?: 'User';
avatar: Scalars['String'];
bio: Maybe<Scalars['String']>;
@@ -395,20 +434,12 @@ export type User = {
linkedin: Maybe<Scalars['String']>;
location: Maybe<Scalars['String']>;
name: Scalars['String'];
nostr_prv_key: Maybe<Scalars['String']>;
nostr_pub_key: Maybe<Scalars['String']>;
role: Maybe<Scalars['String']>;
stories: Array<Story>;
twitter: Maybe<Scalars['String']>;
website: Maybe<Scalars['String']>;
};
export type UserKey = {
__typename?: 'UserKey';
key: Scalars['String'];
name: Scalars['String'];
};
export type UserKeyInputType = {
key: Scalars['String'];
name: Scalars['String'];
@@ -434,6 +465,12 @@ export type Vote = {
payment_request: Scalars['String'];
};
export type WalletKey = {
__typename?: 'WalletKey';
key: Scalars['String'];
name: Scalars['String'];
};
export type OfficialTagsQueryVariables = Exact<{ [key: string]: never; }>;
@@ -454,7 +491,7 @@ export type SearchProjectsQuery = { __typename?: 'Query', searchProjects: Array<
export type MeQueryVariables = Exact<{ [key: string]: never; }>;
export type MeQuery = { __typename?: 'Query', me: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any } | null };
export type MeQuery = { __typename?: 'Query', me: { __typename?: 'MyProfile', id: number, name: string, avatar: string, join_date: any, jobTitle: string | null, bio: string | null } | null };
export type DonationsStatsQueryVariables = Exact<{ [key: string]: never; }>;
@@ -533,31 +570,36 @@ export type PostDetailsQueryVariables = Exact<{
export type PostDetailsQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, applications: Array<{ __typename?: 'BountyApplication', id: number, date: string, workplan: string, author: { __typename?: 'Author', id: number, name: string, avatar: string } }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string | null, is_published: boolean | null, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } };
export type MyWalletsKeysQueryVariables = Exact<{ [key: string]: never; }>;
export type MyProfilePreferencesQueryVariables = Exact<{ [key: string]: never; }>;
export type MyWalletsKeysQuery = { __typename?: 'Query', myWalletsKeys: Array<{ __typename?: 'UserKey', key: string, name: string }> };
export type MyProfilePreferencesQuery = { __typename?: 'Query', me: { __typename?: 'MyProfile', nostr_prv_key: string | null, nostr_pub_key: string | null, walletsKeys: Array<{ __typename?: 'WalletKey', key: string, name: string }> } | null };
export type UpdateUserWalletsKeysMutationVariables = Exact<{
data: InputMaybe<Array<UserKeyInputType> | UserKeyInputType>;
export type UpdateUserPreferencesMutationVariables = Exact<{
userKeys: InputMaybe<Array<UserKeyInputType> | UserKeyInputType>;
}>;
export type UpdateUserWalletsKeysMutation = { __typename?: 'Mutation', updateUserWalletKeys: Array<{ __typename?: 'UserKey', key: string, name: string }> };
export type UpdateUserPreferencesMutation = { __typename?: 'Mutation', updateUserPreferences: Array<{ __typename?: 'MyProfile', nostr_pub_key: string | null, nostr_prv_key: string | null, walletsKeys: Array<{ __typename?: 'WalletKey', key: string, name: string }> }> };
export type MyProfileAboutQueryVariables = Exact<{ [key: string]: never; }>;
export type MyProfileAboutQuery = { __typename?: 'Query', me: { __typename?: 'MyProfile', id: number, name: string, avatar: string, join_date: any, role: string | null, email: string | null, jobTitle: string | null, lightning_address: string | null, website: string | null, twitter: string | null, github: string | null, linkedin: string | null, bio: string | null, location: string | null } | null };
export type UpdateProfileAboutMutationVariables = Exact<{
data: InputMaybe<UpdateProfileInput>;
data: InputMaybe<ProfileDetailsInput>;
}>;
export type UpdateProfileAboutMutation = { __typename?: 'Mutation', updateProfile: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, website: string | null, role: string | null, email: string | null, lightning_address: string | null, jobTitle: string | null, twitter: string | null, github: string | null, linkedin: string | null, bio: string | null, location: string | null } | null };
export type UpdateProfileAboutMutation = { __typename?: 'Mutation', updateProfileDetails: { __typename?: 'MyProfile', id: number, name: string, avatar: string, join_date: any, role: string | null, email: string | null, jobTitle: string | null, lightning_address: string | null, website: string | null, twitter: string | null, github: string | null, linkedin: string | null, bio: string | null, location: string | null } | null };
export type ProfileQueryVariables = Exact<{
profileId: Scalars['Int'];
}>;
export type ProfileQuery = { __typename?: 'Query', profile: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, role: string | null, email: string | null, jobTitle: string | null, lightning_address: string | null, website: string | null, twitter: string | null, github: string | null, linkedin: string | null, bio: string | null, location: string | null, nostr_prv_key: string | null, nostr_pub_key: string | null, stories: Array<{ __typename?: 'Story', id: number, title: string, createdAt: any, tags: Array<{ __typename?: 'Tag', id: number, title: string, icon: string | null }> }> } | null };
export type ProfileQuery = { __typename?: 'Query', profile: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, role: string | null, email: string | null, jobTitle: string | null, lightning_address: string | null, website: string | null, twitter: string | null, github: string | null, linkedin: string | null, bio: string | null, location: string | null, stories: Array<{ __typename?: 'Story', id: number, title: string, createdAt: any, tags: Array<{ __typename?: 'Tag', id: number, title: string, icon: string | null }> }> } | null };
export type CategoryPageQueryVariables = Exact<{
categoryId: Scalars['Int'];
@@ -728,6 +770,8 @@ export const MeDocument = gql`
name
avatar
join_date
jobTitle
bio
}
}
`;
@@ -1336,87 +1380,142 @@ export function usePostDetailsLazyQuery(baseOptions?: Apollo.LazyQueryHookOption
export type PostDetailsQueryHookResult = ReturnType<typeof usePostDetailsQuery>;
export type PostDetailsLazyQueryHookResult = ReturnType<typeof usePostDetailsLazyQuery>;
export type PostDetailsQueryResult = Apollo.QueryResult<PostDetailsQuery, PostDetailsQueryVariables>;
export const MyWalletsKeysDocument = gql`
query MyWalletsKeys {
myWalletsKeys {
key
name
export const MyProfilePreferencesDocument = gql`
query MyProfilePreferences {
me {
walletsKeys {
key
name
}
nostr_prv_key
nostr_pub_key
}
}
`;
/**
* __useMyWalletsKeysQuery__
* __useMyProfilePreferencesQuery__
*
* To run a query within a React component, call `useMyWalletsKeysQuery` and pass it any options that fit your needs.
* When your component renders, `useMyWalletsKeysQuery` returns an object from Apollo Client that contains loading, error, and data properties
* To run a query within a React component, call `useMyProfilePreferencesQuery` and pass it any options that fit your needs.
* When your component renders, `useMyProfilePreferencesQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useMyWalletsKeysQuery({
* const { data, loading, error } = useMyProfilePreferencesQuery({
* variables: {
* },
* });
*/
export function useMyWalletsKeysQuery(baseOptions?: Apollo.QueryHookOptions<MyWalletsKeysQuery, MyWalletsKeysQueryVariables>) {
export function useMyProfilePreferencesQuery(baseOptions?: Apollo.QueryHookOptions<MyProfilePreferencesQuery, MyProfilePreferencesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<MyWalletsKeysQuery, MyWalletsKeysQueryVariables>(MyWalletsKeysDocument, options);
return Apollo.useQuery<MyProfilePreferencesQuery, MyProfilePreferencesQueryVariables>(MyProfilePreferencesDocument, options);
}
export function useMyWalletsKeysLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MyWalletsKeysQuery, MyWalletsKeysQueryVariables>) {
export function useMyProfilePreferencesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MyProfilePreferencesQuery, MyProfilePreferencesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<MyWalletsKeysQuery, MyWalletsKeysQueryVariables>(MyWalletsKeysDocument, options);
return Apollo.useLazyQuery<MyProfilePreferencesQuery, MyProfilePreferencesQueryVariables>(MyProfilePreferencesDocument, options);
}
export type MyWalletsKeysQueryHookResult = ReturnType<typeof useMyWalletsKeysQuery>;
export type MyWalletsKeysLazyQueryHookResult = ReturnType<typeof useMyWalletsKeysLazyQuery>;
export type MyWalletsKeysQueryResult = Apollo.QueryResult<MyWalletsKeysQuery, MyWalletsKeysQueryVariables>;
export const UpdateUserWalletsKeysDocument = gql`
mutation UpdateUserWalletsKeys($data: [UserKeyInputType!]) {
updateUserWalletKeys(data: $data) {
key
name
export type MyProfilePreferencesQueryHookResult = ReturnType<typeof useMyProfilePreferencesQuery>;
export type MyProfilePreferencesLazyQueryHookResult = ReturnType<typeof useMyProfilePreferencesLazyQuery>;
export type MyProfilePreferencesQueryResult = Apollo.QueryResult<MyProfilePreferencesQuery, MyProfilePreferencesQueryVariables>;
export const UpdateUserPreferencesDocument = gql`
mutation UpdateUserPreferences($userKeys: [UserKeyInputType!]) {
updateUserPreferences(userKeys: $userKeys) {
walletsKeys {
key
name
}
nostr_pub_key
nostr_prv_key
}
}
`;
export type UpdateUserWalletsKeysMutationFn = Apollo.MutationFunction<UpdateUserWalletsKeysMutation, UpdateUserWalletsKeysMutationVariables>;
export type UpdateUserPreferencesMutationFn = Apollo.MutationFunction<UpdateUserPreferencesMutation, UpdateUserPreferencesMutationVariables>;
/**
* __useUpdateUserWalletsKeysMutation__
* __useUpdateUserPreferencesMutation__
*
* To run a mutation, you first call `useUpdateUserWalletsKeysMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useUpdateUserWalletsKeysMutation` returns a tuple that includes:
* To run a mutation, you first call `useUpdateUserPreferencesMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useUpdateUserPreferencesMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [updateUserWalletsKeysMutation, { data, loading, error }] = useUpdateUserWalletsKeysMutation({
* const [updateUserPreferencesMutation, { data, loading, error }] = useUpdateUserPreferencesMutation({
* variables: {
* data: // value for 'data'
* userKeys: // value for 'userKeys'
* },
* });
*/
export function useUpdateUserWalletsKeysMutation(baseOptions?: Apollo.MutationHookOptions<UpdateUserWalletsKeysMutation, UpdateUserWalletsKeysMutationVariables>) {
export function useUpdateUserPreferencesMutation(baseOptions?: Apollo.MutationHookOptions<UpdateUserPreferencesMutation, UpdateUserPreferencesMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<UpdateUserWalletsKeysMutation, UpdateUserWalletsKeysMutationVariables>(UpdateUserWalletsKeysDocument, options);
return Apollo.useMutation<UpdateUserPreferencesMutation, UpdateUserPreferencesMutationVariables>(UpdateUserPreferencesDocument, options);
}
export type UpdateUserWalletsKeysMutationHookResult = ReturnType<typeof useUpdateUserWalletsKeysMutation>;
export type UpdateUserWalletsKeysMutationResult = Apollo.MutationResult<UpdateUserWalletsKeysMutation>;
export type UpdateUserWalletsKeysMutationOptions = Apollo.BaseMutationOptions<UpdateUserWalletsKeysMutation, UpdateUserWalletsKeysMutationVariables>;
export const UpdateProfileAboutDocument = gql`
mutation updateProfileAbout($data: UpdateProfileInput) {
updateProfile(data: $data) {
export type UpdateUserPreferencesMutationHookResult = ReturnType<typeof useUpdateUserPreferencesMutation>;
export type UpdateUserPreferencesMutationResult = Apollo.MutationResult<UpdateUserPreferencesMutation>;
export type UpdateUserPreferencesMutationOptions = Apollo.BaseMutationOptions<UpdateUserPreferencesMutation, UpdateUserPreferencesMutationVariables>;
export const MyProfileAboutDocument = gql`
query MyProfileAbout {
me {
id
name
avatar
join_date
website
role
email
lightning_address
jobTitle
lightning_address
website
twitter
github
linkedin
bio
location
}
}
`;
/**
* __useMyProfileAboutQuery__
*
* To run a query within a React component, call `useMyProfileAboutQuery` and pass it any options that fit your needs.
* When your component renders, `useMyProfileAboutQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useMyProfileAboutQuery({
* variables: {
* },
* });
*/
export function useMyProfileAboutQuery(baseOptions?: Apollo.QueryHookOptions<MyProfileAboutQuery, MyProfileAboutQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<MyProfileAboutQuery, MyProfileAboutQueryVariables>(MyProfileAboutDocument, options);
}
export function useMyProfileAboutLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MyProfileAboutQuery, MyProfileAboutQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<MyProfileAboutQuery, MyProfileAboutQueryVariables>(MyProfileAboutDocument, options);
}
export type MyProfileAboutQueryHookResult = ReturnType<typeof useMyProfileAboutQuery>;
export type MyProfileAboutLazyQueryHookResult = ReturnType<typeof useMyProfileAboutLazyQuery>;
export type MyProfileAboutQueryResult = Apollo.QueryResult<MyProfileAboutQuery, MyProfileAboutQueryVariables>;
export const UpdateProfileAboutDocument = gql`
mutation updateProfileAbout($data: ProfileDetailsInput) {
updateProfileDetails(data: $data) {
id
name
avatar
join_date
role
email
jobTitle
lightning_address
website
twitter
github
linkedin
@@ -1478,8 +1577,6 @@ export const ProfileDocument = gql`
icon
}
}
nostr_prv_key
nostr_pub_key
}
}
`;

View File

@@ -1,7 +1,7 @@
import { User } from "src/graphql";
import { MyProfile, User } from "src/graphql";
import { posts } from "./posts";
export const user: User = {
export const user: User & MyProfile = {
id: 123,
email: "mtg0987654321@gmail.com",
avatar: "https://avatars.dicebear.com/api/bottts/Mtgmtg.svg",
@@ -19,4 +19,8 @@ export const user: User = {
stories: posts.stories,
nostr_prv_key: "123123124asdfsadfsa8d7fsadfasdf",
nostr_pub_key: "123124123123dfsadfsa8d7f11sadfasdf",
walletsKeys: [{
key: "1645h234j2421zxvertw",
name: "My alby wallet key"
}]
}

View File

@@ -1,5 +1,5 @@
import { MOCK_DATA } from "./data";
import { Query, QueryGetFeedArgs, QueryGetPostByIdArgs } from 'src/graphql'
import { MyProfile, Query, QueryGetFeedArgs, QueryGetPostByIdArgs } from 'src/graphql'
import { Chance } from "chance";
import { tags } from "./data/tags";
import { hackathons } from "./data/hackathon";
@@ -72,7 +72,7 @@ export function getAllHackathons() {
}
export function me() {
return MOCK_DATA['user']
return MOCK_DATA['user'] as MyProfile
}
export function profile() {

View File

@@ -8,7 +8,7 @@ import { InsertLinkModal } from 'src/Components/Inputs/TextEditor/InsertLinkModa
import { Claim_FundWithdrawCard, Claim_CopySignatureCard, Claim_GenerateSignatureCard, Claim_SubmittedCard } from "src/features/Projects/pages/ProjectPage/ClaimProject";
import { ModalCard } from "src/Components/Modals/ModalsContainer/ModalsContainer";
import { ConfirmModal } from "src/Components/Modals/ConfirmModal";
import { LinkingAccountModal } from "src/features/Profiles/pages/EditProfilePage/AccountCard/LinkingAccountModal";
import { LinkingAccountModal } from "src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkingAccountModal";
import { ComponentProps } from "react";
import { generateId } from "src/utils/helperFunctions";

View File

@@ -1,12 +1,14 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { MyProfile } from "src/graphql";
interface StoreState {
me: {
id: number;
name: string;
avatar: string;
join_date: string;
}
me: Pick<MyProfile,
| 'id'
| "name"
| "avatar"
| "bio"
| "jobTitle"
| 'join_date'>
| undefined // fetching user data if exist
| null // user not logged in