mirror of
https://github.com/aljazceru/landscape-template.git
synced 2025-12-30 12:34:19 +01:00
@@ -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,18 @@ 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!
|
||||
}
|
||||
}
|
||||
|
||||
export interface NexusGenEnums {
|
||||
@@ -137,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!
|
||||
@@ -198,8 +220,6 @@ 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
|
||||
@@ -213,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'];
|
||||
}
|
||||
|
||||
@@ -313,9 +338,30 @@ export interface NexusGenFieldTypes {
|
||||
createStory: NexusGenRootTypes['Story'] | null; // Story
|
||||
deleteStory: NexusGenRootTypes['Story'] | null; // Story
|
||||
donate: NexusGenRootTypes['Donation']; // Donation!
|
||||
updateProfile: NexusGenRootTypes['User'] | null; // User
|
||||
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!
|
||||
@@ -352,7 +398,7 @@ export interface NexusGenFieldTypes {
|
||||
getProject: NexusGenRootTypes['Project']; // Project!
|
||||
getTrendingPosts: NexusGenRootTypes['Post'][]; // [Post!]!
|
||||
hottestProjects: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
me: NexusGenRootTypes['User'] | null; // User
|
||||
me: NexusGenRootTypes['MyProfile'] | null; // MyProfile
|
||||
newProjects: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
officialTags: NexusGenRootTypes['Tag'][]; // [Tag!]!
|
||||
popularTags: NexusGenRootTypes['Tag'][]; // [Tag!]!
|
||||
@@ -408,8 +454,6 @@ 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
|
||||
@@ -424,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!
|
||||
@@ -522,9 +587,30 @@ export interface NexusGenFieldTypeNames {
|
||||
createStory: 'Story'
|
||||
deleteStory: 'Story'
|
||||
donate: 'Donation'
|
||||
updateProfile: 'User'
|
||||
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'
|
||||
@@ -561,7 +647,7 @@ export interface NexusGenFieldTypeNames {
|
||||
getProject: 'Project'
|
||||
getTrendingPosts: 'Post'
|
||||
hottestProjects: 'Project'
|
||||
me: 'User'
|
||||
me: 'MyProfile'
|
||||
newProjects: 'Project'
|
||||
officialTags: 'Tag'
|
||||
popularTags: 'Tag'
|
||||
@@ -617,8 +703,6 @@ export interface NexusGenFieldTypeNames {
|
||||
linkedin: 'String'
|
||||
location: 'String'
|
||||
name: 'String'
|
||||
nostr_prv_key: 'String'
|
||||
nostr_pub_key: 'String'
|
||||
role: 'String'
|
||||
stories: 'Story'
|
||||
twitter: 'String'
|
||||
@@ -633,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'
|
||||
@@ -664,8 +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
|
||||
}
|
||||
updateUserPreferences: { // args
|
||||
userKeys?: NexusGenInputs['UserKeyInputType'][] | null; // [UserKeyInputType!]
|
||||
}
|
||||
vote: { // args
|
||||
amount_in_sat: number; // Int!
|
||||
@@ -730,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;
|
||||
@@ -753,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: {
|
||||
|
||||
@@ -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,10 +117,32 @@ type Mutation {
|
||||
createStory(data: StoryInputType): Story
|
||||
deleteStory(id: Int!): Story
|
||||
donate(amount_in_sat: Int!): Donation!
|
||||
updateProfile(data: UpdateProfileInput): User
|
||||
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
|
||||
@@ -131,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!
|
||||
@@ -160,7 +214,7 @@ type Query {
|
||||
getProject(id: Int!): Project!
|
||||
getTrendingPosts: [Post!]!
|
||||
hottestProjects(skip: Int = 0, take: Int = 50): [Project!]!
|
||||
me: User
|
||||
me: MyProfile
|
||||
newProjects(skip: Int = 0, take: Int = 50): [Project!]!
|
||||
officialTags: [Tag!]!
|
||||
popularTags: [Tag!]!
|
||||
@@ -217,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
|
||||
@@ -243,14 +283,17 @@ type User {
|
||||
linkedin: String
|
||||
location: String
|
||||
name: String!
|
||||
nostr_prv_key: String
|
||||
nostr_pub_key: String
|
||||
role: String
|
||||
stories: [Story!]!
|
||||
twitter: String
|
||||
website: String
|
||||
}
|
||||
|
||||
input UserKeyInputType {
|
||||
key: String!
|
||||
name: String!
|
||||
}
|
||||
|
||||
enum VOTE_ITEM_TYPE {
|
||||
Bounty
|
||||
PostComment
|
||||
@@ -268,4 +311,9 @@ type Vote {
|
||||
paid: Boolean!
|
||||
payment_hash: String!
|
||||
payment_request: String!
|
||||
}
|
||||
|
||||
type WalletKey {
|
||||
key: String!
|
||||
name: String!
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
|
||||
const { prisma } = require('../../../prisma');
|
||||
const { objectType, extendType, intArg, nonNull, inputObjectType } = 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,35 @@ 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 +69,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 +87,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 +110,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,14 +139,103 @@ const updateProfile = extendType({
|
||||
})
|
||||
|
||||
|
||||
const WalletKey = objectType({
|
||||
name: 'WalletKey',
|
||||
definition(t) {
|
||||
t.nonNull.string('key');
|
||||
t.nonNull.string('name');
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
const UserKeyInputType = inputObjectType({
|
||||
name: 'UserKeyInputType',
|
||||
definition(t) {
|
||||
t.nonNull.string('key');
|
||||
t.nonNull.string('name');
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
const updateUserPreferences = extendType({
|
||||
type: 'Mutation',
|
||||
definition(t) {
|
||||
t.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({
|
||||
where: {
|
||||
AND: {
|
||||
user_id: {
|
||||
equals: user.id,
|
||||
},
|
||||
key: {
|
||||
in: args.userKeys.map(i => i.key)
|
||||
}
|
||||
},
|
||||
},
|
||||
select: {
|
||||
key: true
|
||||
}
|
||||
})).map(i => i.key);
|
||||
|
||||
const newKeys = [];
|
||||
for (let i = 0; i < args.userKeys.length; i++) {
|
||||
const item = args.userKeys[i];
|
||||
if (userKeys.includes(item.key))
|
||||
newKeys.push(item);
|
||||
}
|
||||
|
||||
|
||||
if (newKeys.length === 0)
|
||||
throw new Error("You can't delete all your wallets keys")
|
||||
|
||||
await prisma.userKey.deleteMany({
|
||||
where: {
|
||||
user_id: user.id
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.userKey.createMany({
|
||||
data: newKeys.map(i => ({
|
||||
user_id: user.id,
|
||||
key: i.key,
|
||||
name: i.name,
|
||||
}))
|
||||
})
|
||||
|
||||
return prisma.user.findUnique({ where: { id: user.id } });
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = {
|
||||
// Types
|
||||
BaseUser,
|
||||
User,
|
||||
UpdateProfileInput,
|
||||
MyProfile,
|
||||
WalletKey,
|
||||
// Queries
|
||||
me,
|
||||
profile,
|
||||
// Mutations
|
||||
updateProfile,
|
||||
}
|
||||
updateProfileDetails,
|
||||
updateUserPreferences,
|
||||
}
|
||||
|
||||
@@ -37,15 +37,11 @@ const loginHandler = async (req, res) => {
|
||||
if (existingKeys.length >= 3)
|
||||
return res.status(400).json({ status: 'ERROR', reason: "Can only link up to 3 wallets" })
|
||||
|
||||
if (existingKeys.includes(key))
|
||||
return res.status(400).json({ status: 'ERROR', reason: "Wallet already linked" });
|
||||
|
||||
// Remove old linking for this key if existing
|
||||
await prisma.userKey.deleteMany({
|
||||
where: { key }
|
||||
})
|
||||
|
||||
|
||||
await prisma.userKey.create({
|
||||
data: {
|
||||
key,
|
||||
@@ -53,6 +49,7 @@ const loginHandler = async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return res
|
||||
.status(200)
|
||||
.json({ status: "OK" })
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "UserKey" ADD COLUMN "name" TEXT NOT NULL DEFAULT E'New Key Name';
|
||||
21
public/assets/icons/nut.svg
Normal file
21
public/assets/icons/nut.svg
Normal file
@@ -0,0 +1,21 @@
|
||||
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.1645 2.44122L13.8999 1.89167L13.2918 1.93933L5.88553 2.51977L5.44117 2.5546L5.20243 2.931L2.07304 7.86481L1.81474 8.27205L2.01427 8.71108L4.91607 15.096L5.13423 15.5761L5.66001 15.616L13.2938 16.1965L13.9287 16.2448L14.1803 15.6599L17.0157 9.06762L17.1762 8.69453L16.9999 8.32862L14.1645 2.44122Z" fill="#C4C4C4" stroke="#333333" stroke-width="1.78281"/>
|
||||
<g filter="url(#filter0_i_1824_6762)">
|
||||
<path d="M13.3614 2.82806L5.95518 3.40851L2.82579 8.34232L5.72759 14.7273L13.3614 15.3077L16.1968 8.71547L13.3614 2.82806Z" fill="url(#paint0_linear_1824_6762)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_i_1824_6762" x="2.82579" y="2.82806" width="13.371" height="12.4796" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dx="-0.445701" dy="1.3371"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0.9375 0 0 0 0 0.9375 0 0 0 0 0.9375 0 0 0 0.25 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1824_6762"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_1824_6762" x1="9.51131" y1="2.82806" x2="9.51131" y2="15.3077" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.286458" stop-color="#B7B7B7"/>
|
||||
<stop offset="1" stop-color="#9B9B9B"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/assets/images/nut_3d.png
Normal file
BIN
public/assets/images/nut_3d.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.9 KiB |
@@ -25,7 +25,7 @@ const btnStylesFill: UnionToObjectKeys<Props, 'color'> = {
|
||||
gray: 'bg-gray-100 hover:bg-gray-200 text-gray-900 active:bg-gray-300',
|
||||
white: 'border border-gray-300 text-gray-900 bg-gray-25 hover:bg-gray-50',
|
||||
black: 'text-white bg-black hover:bg-gray-900',
|
||||
red: "bg-red-600 hover:bg-red-500 active:bg-red-700 text-white",
|
||||
red: "bg-red-500 hover:bg-red-600 active:bg-red-700 text-white",
|
||||
}
|
||||
|
||||
const loadingColor: UnionToObjectKeys<Props, 'color'> = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { Link } from 'react-router-dom'
|
||||
import { UnionToObjectKeys } from 'src/utils/types/utils'
|
||||
|
||||
@@ -6,7 +6,6 @@ interface Props {
|
||||
onClick?: () => void;
|
||||
onKeyDown?: (v: any) => void
|
||||
href?: string;
|
||||
children: JSX.Element
|
||||
className?: string
|
||||
size?: "sm" | 'md' | 'lg'
|
||||
variant?: 'blank' | 'fill'
|
||||
@@ -26,7 +25,7 @@ const baseBtnStyles: UnionToObjectKeys<Props, 'variant'> = {
|
||||
blank: "bg-gray-900 bg-opacity-0 hover:bg-opacity-5 active:bg-opacity-10 active:scale-95 !border-0"
|
||||
}
|
||||
|
||||
const IconButton = React.forwardRef<any, Props>(({
|
||||
const IconButton = React.forwardRef<any, PropsWithChildren<Props>>(({
|
||||
href,
|
||||
size = "md",
|
||||
className = "",
|
||||
|
||||
@@ -153,20 +153,29 @@ export default function LoginPage() {
|
||||
</div>
|
||||
|
||||
else
|
||||
content = <div className="max-w-[326px] border-2 border-gray-200 rounded-16 p-16 flex flex-col gap-16 items-center" >
|
||||
<p className="text-body1 font-bolder text-center">
|
||||
Login with lightning ⚡
|
||||
</p>
|
||||
<QRCodeSVG
|
||||
width={160}
|
||||
height={160}
|
||||
value={lnurl}
|
||||
/>
|
||||
content = <div className="max-w-[364px] border-2 border-gray-200 rounded-16 p-16 flex flex-col gap-24 items-center" >
|
||||
|
||||
<h2 className='text-h5 font-bold text-center'>Login with lightning ⚡</h2>
|
||||
<a href={`lightning:${lnurl}`} >
|
||||
<QRCodeSVG
|
||||
width={240}
|
||||
height={240}
|
||||
value={lnurl}
|
||||
bgColor='transparent'
|
||||
imageSettings={{
|
||||
src: '/assets/images/nut_3d.png',
|
||||
width: 32,
|
||||
height: 32,
|
||||
excavate: true,
|
||||
|
||||
}}
|
||||
/>
|
||||
</a>
|
||||
<p className="text-gray-600 text-body4 text-center">
|
||||
Scan this code or copy + paste it to your lightning wallet. Or click to login with your browser's wallet.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-16">
|
||||
<a href={lnurl}
|
||||
<div className="w-full flex flex-col items-stretch gap-16">
|
||||
<a href={`lightning:${lnurl}`}
|
||||
className='grow block text-body4 text-center text-white font-bolder bg-primary-500 hover:bg-primary-600 rounded-10 px-16 py-12 active:scale-90 transition-transform'
|
||||
>Click to connect <IoRocketOutline /></a>
|
||||
<Button
|
||||
|
||||
@@ -4,5 +4,7 @@ query Me {
|
||||
name
|
||||
avatar
|
||||
join_date
|
||||
jobTitle
|
||||
bio
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Avatar from 'src/features/Profiles/Components/Avatar/Avatar';
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,36 +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';
|
||||
|
||||
|
||||
interface Props {
|
||||
|
||||
}
|
||||
|
||||
export default function AccountCard({ }: Props) {
|
||||
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const connectNewWallet = () => {
|
||||
dispatch(openModal({ Modal: "LinkingAccountModal" }))
|
||||
}
|
||||
|
||||
|
||||
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>
|
||||
<Button color='primary' className='' onClick={connectNewWallet}>
|
||||
Connect new wallet ⚡
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
@@ -17,12 +16,8 @@ const links = [
|
||||
text: "👾 My Profile",
|
||||
path: 'my-profile',
|
||||
},
|
||||
// {
|
||||
// text: "🙍♂️ Account",
|
||||
// path: 'account',
|
||||
// },
|
||||
{
|
||||
text: "⚙️ Preferences",
|
||||
text: "⚙️ Settings & Preferences",
|
||||
path: 'preferences',
|
||||
}
|
||||
]
|
||||
@@ -30,24 +25,16 @@ 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);
|
||||
|
||||
|
||||
const user = useAppSelector(state => state.user.me)
|
||||
|
||||
|
||||
if (!userId || profileQuery.loading)
|
||||
if (!user)
|
||||
return <LoadingPage />
|
||||
|
||||
if (!profileQuery.data?.profile)
|
||||
return <NotFoundPage />
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
@@ -97,9 +84,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>
|
||||
|
||||
@@ -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',
|
||||
@@ -0,0 +1,87 @@
|
||||
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 WalletKey from './WalletKey';
|
||||
|
||||
|
||||
export type WalletKeyType = MyProfile['walletsKeys'][number]
|
||||
|
||||
interface Props {
|
||||
value: WalletKeyType[],
|
||||
onChange: (newValue: WalletKeyType[]) => void
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default function LinkedAccountsCard({ value, onChange }: Props) {
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const connectNewWallet = () => {
|
||||
dispatch(openModal({ Modal: "LinkingAccountModal" }))
|
||||
}
|
||||
|
||||
const updateKeyName = (idx: number, newName: string) => {
|
||||
onChange(value.map((item, i) => {
|
||||
if (i === idx)
|
||||
return {
|
||||
...item,
|
||||
name: newName
|
||||
}
|
||||
return item;
|
||||
}))
|
||||
}
|
||||
|
||||
const deleteKey = (idx: number,) => {
|
||||
onChange([...value.slice(0, idx), ...value.slice(idx + 1)])
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<p className="text-body2 font-bold">🔐 Linked Wallets</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 up to 3 wallets.
|
||||
</p>
|
||||
<div className='mt-24 flex flex-col gap-16'>
|
||||
<ul className="mt-8 relative flex flex-col gap-8">
|
||||
{value.map((item, idx) =>
|
||||
<WalletKey
|
||||
key={idx}
|
||||
walletKey={item}
|
||||
canDelete={value.length > 1}
|
||||
onRename={v => updateKeyName(idx, v)}
|
||||
onDelete={() => deleteKey(idx)}
|
||||
/>
|
||||
)}
|
||||
</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> */}
|
||||
</div>
|
||||
{value.length < 3 &&
|
||||
<Button color='none' size='sm' className='mt-16 text-gray-600 hover:bg-gray-50' onClick={connectNewWallet}>
|
||||
+ Add another wallet
|
||||
</Button>}
|
||||
<p className="text-body5 text-gray-400 mt-24"><span className="font-bold">Note</span>: if you link a wallet that was used to create another account previously, you won't be able to login to that account until you remove it from here.</p>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import { useToggle } from '@react-hookz/web';
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { FiTrash2 } from 'react-icons/fi';
|
||||
import Button from 'src/Components/Button/Button';
|
||||
import IconButton from 'src/Components/IconButton/IconButton';
|
||||
import { useReduxEffect } from 'src/utils/hooks/useReduxEffect';
|
||||
import { WalletKeyType } from './LinkedAccountsCard'
|
||||
import { useAppDispatch } from "src/utils/hooks";
|
||||
import { openModal } from "src/redux/features/modals.slice";
|
||||
|
||||
interface Props {
|
||||
walletKey: WalletKeyType,
|
||||
canDelete: boolean;
|
||||
onRename: (newName: string) => void
|
||||
onDelete: () => void
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default function WalletKey({ walletKey, canDelete, onRename, onDelete }: Props) {
|
||||
|
||||
const ref = useRef<HTMLInputElement>(null!);
|
||||
const [name, setName] = useState(walletKey.name);
|
||||
const [editMode, toggleEditMode] = useToggle(false);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
|
||||
const CONFIRM_DELETE_WALLET = useMemo(() => createAction<{ confirmed?: boolean }>(`CONFIRM_DELETE_WALLET_${walletKey.key.slice(0, 10)}`)({}), [walletKey.key])
|
||||
|
||||
const saveNameChanges = () => {
|
||||
toggleEditMode();
|
||||
onRename(name);
|
||||
}
|
||||
|
||||
const onConfirmDelete = useCallback(({ payload: { confirmed } }: typeof CONFIRM_DELETE_WALLET) => {
|
||||
if (confirmed)
|
||||
onDelete()
|
||||
}, [onDelete])
|
||||
|
||||
useReduxEffect(onConfirmDelete, CONFIRM_DELETE_WALLET.type);
|
||||
|
||||
useEffect(() => {
|
||||
if (editMode)
|
||||
ref.current.focus()
|
||||
}, [editMode])
|
||||
|
||||
const handleDelete = () => {
|
||||
dispatch(openModal({
|
||||
Modal: "RemoveWalletKeyModal",
|
||||
props: {
|
||||
callbackAction: {
|
||||
type: CONFIRM_DELETE_WALLET.type,
|
||||
payload: { confirmed: false }
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
return (
|
||||
<li key={walletKey.key} className="flex gap-16 items-center">
|
||||
<div className="input-wrapper relative min-w-0">
|
||||
<span className="input-icon !pr-0">🔑</span>
|
||||
<input
|
||||
ref={ref}
|
||||
disabled={!editMode}
|
||||
type='text'
|
||||
value={name}
|
||||
className="input-text overflow-hidden text-ellipsis"
|
||||
placeholder='e.g My Alby Key'
|
||||
onChange={e => setName(e.target.value)}
|
||||
/>
|
||||
{!editMode && <Button size='sm' color='none' className='text-blue-400 shrink-0' onClick={() => toggleEditMode()}>Rename</Button>}
|
||||
{editMode &&
|
||||
<Button
|
||||
size='sm'
|
||||
color='none'
|
||||
className='text-blue-400 shrink-0'
|
||||
disabled={name.length === 0}
|
||||
onClick={saveNameChanges}
|
||||
>Save</Button>}
|
||||
</div>
|
||||
{canDelete && <IconButton
|
||||
size='sm'
|
||||
className='text-red-500 shrink-0'
|
||||
onClick={() => handleDelete()}
|
||||
><FiTrash2 /> </IconButton>}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import { QRCodeSVG } from 'qrcode.react';
|
||||
import Button from "src/Components/Button/Button";
|
||||
import { FiCopy } from "react-icons/fi";
|
||||
import useCopyToClipboard from "src/utils/hooks/useCopyToClipboard";
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { IoClose } from 'react-icons/io5';
|
||||
|
||||
|
||||
|
||||
@@ -57,7 +59,8 @@ export default function LinkingAccountModal({ onClose, direction, ...props }: Mo
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const { loadingLnurl, data: { lnurl }, error } = useLnurlQuery();
|
||||
const clipboard = useCopyToClipboard()
|
||||
const clipboard = useCopyToClipboard();
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
|
||||
|
||||
@@ -71,41 +74,49 @@ export default function LinkingAccountModal({ onClose, direction, ...props }: Mo
|
||||
clipboard(lnurl);
|
||||
}
|
||||
|
||||
const done = () => {
|
||||
apolloClient.refetchQueries({
|
||||
include: ['MyProfilePreferences']
|
||||
})
|
||||
onClose?.()
|
||||
}
|
||||
|
||||
|
||||
let content = <></>
|
||||
|
||||
if (error)
|
||||
content = <div className="flex flex-col gap-24 items-center">
|
||||
<p className="text-body3 text-red-500 font-bold">Something wrong happened...</p>
|
||||
<a href='/login' className="text body4 text-gray-500 hover:underline">Refresh the page</a>
|
||||
content = <div className="flex flex-col gap-24 items-center my-32">
|
||||
<p className="text-body3 text-red-500 font-bold">Ooops...😵</p>
|
||||
<p className="text-body4 text-gray-600 text-center">An error happened while fetching the link, please check your internet connection and try again.</p>
|
||||
</div>
|
||||
|
||||
else if (loadingLnurl)
|
||||
content = <div className="flex flex-col gap-24 items-center">
|
||||
<Grid color="var(--primary)" width="150" />
|
||||
<p className="text-body3 font-bold">Fetching Lnurl-Auth...</p>
|
||||
content = <div className="flex flex-col gap-24 items-center my-32">
|
||||
<Grid color="var(--primary)" width="80" />
|
||||
<p className="text-body4 text-gray-600 font-bold">Fetching Lnurl-Auth Link...</p>
|
||||
</div>
|
||||
|
||||
else
|
||||
content =
|
||||
<>
|
||||
<p className="text-body1 font-bolder text-center">
|
||||
Link your account ⚡
|
||||
</p>
|
||||
<QRCodeSVG
|
||||
width={160}
|
||||
height={160}
|
||||
value={lnurl}
|
||||
/>
|
||||
<div className='flex flex-col gap-24 items-center mt-32 '>
|
||||
<a href={`lightning:${lnurl}`} >
|
||||
<QRCodeSVG
|
||||
width={240}
|
||||
height={240}
|
||||
value={lnurl}
|
||||
bgColor='transparent'
|
||||
imageSettings={{
|
||||
src: '/assets/images/nut_3d.png',
|
||||
width: 32,
|
||||
height: 32,
|
||||
excavate: true
|
||||
}}
|
||||
/>
|
||||
</a>
|
||||
<p className="text-gray-600 text-body4 text-center">
|
||||
Scan this code or copy + paste it to your other lightning wallet to be able to login later with it to this account.
|
||||
<br />
|
||||
When done, click the button below to close this modal.
|
||||
Scan this code or copy + paste it to your lightning wallet to connect another account to your maker profile. You can also click the QR code to open your WebLN wallet. When done, click the button below to close this modal.
|
||||
</p>
|
||||
<div className="flex flex-col w-full gap-16">
|
||||
{/* <a href={lnurl}
|
||||
className='grow block text-body4 text-center text-white font-bolder bg-primary-500 hover:bg-primary-600 rounded-10 px-16 py-12 active:scale-90 transition-transform'
|
||||
>Click to connect <IoRocketOutline /></a> */}
|
||||
<Button
|
||||
color='gray'
|
||||
className='grow'
|
||||
@@ -114,14 +125,13 @@ export default function LinkingAccountModal({ onClose, direction, ...props }: Mo
|
||||
>{copied ? "Copied" : "Copy"} <FiCopy /></Button>
|
||||
<Button
|
||||
color='primary'
|
||||
onClick={onClose}
|
||||
onClick={done}
|
||||
fullWidth
|
||||
className='mt-16'
|
||||
>
|
||||
Done?
|
||||
Done
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -132,8 +142,10 @@ export default function LinkingAccountModal({ onClose, direction, ...props }: Mo
|
||||
initial='initial'
|
||||
animate="animate"
|
||||
exit='exit'
|
||||
className="modal-card w-full max-w-[326px] bg-white border-2 border-gray-200 rounded-16 p-16 flex flex-col gap-16 items-center"
|
||||
className="modal-card max-w-[442px] p-24 rounded-xl relative"
|
||||
>
|
||||
<IoClose className='absolute text-body2 top-24 right-24 hover:cursor-pointer' onClick={onClose} />
|
||||
<h2 className='text-h5 font-bold text-center'>Connect another ⚡️ wallet</h2>
|
||||
{content}
|
||||
</motion.div>
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from 'react'
|
||||
import Card from 'src/Components/Card/Card';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
|
||||
export default function PreferencesTabSkeleton() {
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-24">
|
||||
<div className="col-span-2 flex flex-col gap-24">
|
||||
<Card>
|
||||
<p className="text-body2 font-bold"><Skeleton width="15ch" /></p>
|
||||
<p className="text-body4 text-gray-600 mt-8">
|
||||
<Skeleton width="70%" />
|
||||
<Skeleton width="35%" />
|
||||
</p>
|
||||
|
||||
<div className='mt-24 flex flex-col gap-16'>
|
||||
<ul className="mt-8 relative flex flex-col gap-8">
|
||||
{Array(3).fill(0).map((_, idx) =>
|
||||
<li key={idx} className="flex flex-wrap gap-16 justify-between items-center text-body4 border-b py-12 px-16 border border-gray-200 rounded-16 focus-within:ring-1 ring-primary-200">
|
||||
<div className='p-0 border-0 focus:border-0 focus:outline-none grow
|
||||
focus:ring-0 placeholder:!text-gray-400' >
|
||||
<Skeleton width='20ch'></Skeleton>
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<p className="text-body2 font-bold"><Skeleton width="12ch" /></p>
|
||||
<p className="text-body4 text-gray-600 mt-8">
|
||||
<Skeleton width="80%" />
|
||||
<Skeleton width="50%" />
|
||||
<Skeleton width="65%" />
|
||||
</p>
|
||||
<div className="py-42"></div>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,20 +1,105 @@
|
||||
import { Nullable } from 'remirror';
|
||||
import LinkedAccountsCard from './LinkedAccountsCard/LinkedAccountsCard';
|
||||
import CommentsSettingsCard from './CommentsSettingsCard/CommentsSettingsCard';
|
||||
import { UpdateUserPreferencesMutationVariables, useMyProfilePreferencesQuery, useUpdateUserPreferencesMutation } from 'src/graphql';
|
||||
import NotFoundPage from "src/features/Shared/pages/NotFoundPage/NotFoundPage";
|
||||
import PreferencesTabSkeleton from './PreferencesTab.Skeleton'
|
||||
import * as yup from "yup";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
|
||||
import SaveChangesCard from '../SaveChangesCard/SaveChangesCard';
|
||||
import { toast } from 'react-toastify';
|
||||
import { NotificationsService } from 'src/services';
|
||||
import { NetworkStatus } from '@apollo/client';
|
||||
import { usePrompt } from 'src/utils/hooks';
|
||||
|
||||
|
||||
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 type IProfilePreferencesForm = NonNullable<UpdateUserPreferencesMutationVariables>;
|
||||
|
||||
const schema: yup.SchemaOf<IProfilePreferencesForm> = yup.object({
|
||||
walletsKeys: yup.array().of(yup.object().shape({
|
||||
name: yup.string().required(),
|
||||
key: yup.string().trim().required(),
|
||||
}).required())
|
||||
.required(),
|
||||
}).required();
|
||||
|
||||
export default function PreferencesTab() {
|
||||
|
||||
const { formState: { isDirty, }, handleSubmit, reset, control } = useForm<IProfilePreferencesForm>({
|
||||
defaultValues: {
|
||||
walletsKeys: []
|
||||
},
|
||||
resolver: yupResolver(schema),
|
||||
});
|
||||
|
||||
const query = useMyProfilePreferencesQuery({
|
||||
onCompleted: data => {
|
||||
if (data.me) reset(data.me)
|
||||
},
|
||||
notifyOnNetworkStatusChange: true,
|
||||
});
|
||||
const [mutate, mutationStatus] = useUpdateUserPreferencesMutation();
|
||||
|
||||
|
||||
usePrompt('You may have some unsaved changes. You still want to leave?', isDirty)
|
||||
|
||||
|
||||
if (query.networkStatus === NetworkStatus.loading)
|
||||
return <PreferencesTabSkeleton />
|
||||
|
||||
if (!query.data?.me)
|
||||
return <NotFoundPage />
|
||||
|
||||
|
||||
const onSubmit: SubmitHandler<IProfilePreferencesForm> = data => {
|
||||
if (!Array.isArray(data.walletsKeys))
|
||||
return;
|
||||
|
||||
const toastId = toast.loading("Saving changes...", NotificationsService.defaultOptions)
|
||||
|
||||
|
||||
mutate({
|
||||
variables: {
|
||||
walletsKeys: data.walletsKeys.map(({ key, name }) => ({ key, name })),
|
||||
},
|
||||
onCompleted: ({ updateUserPreferences }) => {
|
||||
if (updateUserPreferences) {
|
||||
reset(updateUserPreferences);
|
||||
toast.update(toastId, { render: "Saved changes successfully", type: "success", ...NotificationsService.defaultOptions, isLoading: false });
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
toast.update(toastId, { render: "A network error happened", type: "error", ...NotificationsService.defaultOptions, isLoading: false });
|
||||
mutationStatus.reset()
|
||||
})
|
||||
};
|
||||
|
||||
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">
|
||||
<Controller
|
||||
control={control}
|
||||
name="walletsKeys"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<LinkedAccountsCard value={value as any} onChange={v => {
|
||||
onChange(v);
|
||||
handleSubmit(onSubmit)();
|
||||
}} />
|
||||
)}
|
||||
/>
|
||||
<CommentsSettingsCard nostr_prv_key={query.data.me.nostr_prv_key} nostr_pub_key={query.data.me.nostr_pub_key} />
|
||||
</div>
|
||||
<div className="self-start sticky-side-element">
|
||||
{/* <SaveChangesCard
|
||||
isLoading={mutationStatus.loading}
|
||||
isDirty={isDirty}
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
onCancel={() => reset()}
|
||||
/> */}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { ModalCard, modalCardVariants } from 'src/Components/Modals/ModalsContainer/ModalsContainer'
|
||||
import { motion } from 'framer-motion'
|
||||
import { IoClose } from 'react-icons/io5'
|
||||
import Button from 'src/Components/Button/Button'
|
||||
import { useAppDispatch } from 'src/utils/hooks'
|
||||
import { PayloadAction } from '@reduxjs/toolkit'
|
||||
|
||||
interface Props extends ModalCard {
|
||||
callbackAction: PayloadAction<{ confirmed: boolean }>
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default function RemoveWalletKeyModal({
|
||||
onClose, direction, callbackAction,
|
||||
}: Props) {
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleConfirm = () => {
|
||||
const action = Object.assign({}, callbackAction);
|
||||
action.payload = { confirmed: true }
|
||||
dispatch(action)
|
||||
onClose?.();
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
custom={direction}
|
||||
variants={modalCardVariants}
|
||||
initial='initial'
|
||||
animate="animate"
|
||||
exit='exit'
|
||||
className="modal-card max-w-[326px] p-24 rounded-xl relative"
|
||||
>
|
||||
<IoClose className='absolute text-body2 top-24 right-24 hover:cursor-pointer' onClick={onClose} />
|
||||
<h2 className='text-h5 font-bold text-center'>Remove key?</h2>
|
||||
<div className="pt-16 flex flex-col gap-24 mt-16">
|
||||
<p className="text-h1 text-center">🔑</p>
|
||||
<p className="text-body4 text-gray-600 text-center font-light">Are you sure you want to remove this key from your account? Once deleted, you won’t be able to recover it.</p>
|
||||
<div className="grid grid-cols-2 gap-16">
|
||||
<Button color='gray' onClick={onClose} >Cancel</Button>
|
||||
<Button color='red' onClick={handleConfirm} >Remove</Button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { lazyModal } from 'src/utils/helperFunctions';
|
||||
|
||||
export const { LazyComponent: RemoveWalletKeyModal } = lazyModal(() => import('./RemoveWalletKeyModal'))
|
||||
@@ -0,0 +1,23 @@
|
||||
query MyProfilePreferences {
|
||||
me {
|
||||
id
|
||||
walletsKeys {
|
||||
key
|
||||
name
|
||||
}
|
||||
nostr_prv_key
|
||||
nostr_pub_key
|
||||
}
|
||||
}
|
||||
|
||||
mutation UpdateUserPreferences($walletsKeys: [UserKeyInputType!]) {
|
||||
updateUserPreferences(userKeys: $walletsKeys) {
|
||||
id
|
||||
walletsKeys {
|
||||
key
|
||||
name
|
||||
}
|
||||
nostr_pub_key
|
||||
nostr_prv_key
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import { Link } from 'react-router-dom'
|
||||
import Button from 'src/Components/Button/Button'
|
||||
import Card from 'src/Components/Card/Card'
|
||||
import Avatar from 'src/features/Profiles/Components/Avatar/Avatar'
|
||||
import { useProfileQuery } from 'src/graphql'
|
||||
import { trimText } from 'src/utils/helperFunctions'
|
||||
import { useAppSelector } from 'src/utils/hooks'
|
||||
import { createRoute } from 'src/utils/routing'
|
||||
@@ -17,14 +16,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 +33,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"
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import Card from 'src/Components/Card/Card';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
|
||||
export default function UpdateProfileAboutTabSkeleton() {
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-24">
|
||||
<div className="col-span-2 flex flex-col gap-24">
|
||||
<Card className="md:col-span-2" defaultPadding={false}>
|
||||
<div className="bg-gray-100 relative h-[160px] rounded-t-16">
|
||||
<div className="absolute left-24 bottom-0 translate-y-1/2">
|
||||
<div className="w-[120px] aspect-square rounded-full bg-gray-50 border border-gray-200"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-16 md:p-24 mt-64">
|
||||
|
||||
<p className="text-body2 font-bold"><Skeleton width="12ch" /></p>
|
||||
<p className="text-body4 text-gray-600 mt-8">
|
||||
<Skeleton width="50%" />
|
||||
</p>
|
||||
<div className="py-[250px]"></div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,33 +1,23 @@
|
||||
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";
|
||||
import UpdateProfileAboutTabSkeleton from "./UpdateMyProfileTab.Skeleton";
|
||||
|
||||
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 +53,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 <UpdateProfileAboutTabSkeleton />
|
||||
|
||||
if (!profileQuery.data?.me)
|
||||
return <NotFoundPage />
|
||||
|
||||
|
||||
const onSubmit: SubmitHandler<IFormInputs> = data => {
|
||||
|
||||
const toastId = toast.loading("Saving changes...", NotificationsService.defaultOptions)
|
||||
@@ -98,9 +102,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 +121,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">
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,5 @@ query profile($profileId: Int!) {
|
||||
icon
|
||||
}
|
||||
}
|
||||
nostr_prv_key
|
||||
nostr_pub_key
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,7 +139,8 @@ export type Mutation = {
|
||||
createStory: Maybe<Story>;
|
||||
deleteStory: Maybe<Story>;
|
||||
donate: Donation;
|
||||
updateProfile: Maybe<User>;
|
||||
updateProfileDetails: Maybe<MyProfile>;
|
||||
updateUserPreferences: MyProfile;
|
||||
vote: Vote;
|
||||
};
|
||||
|
||||
@@ -153,8 +172,13 @@ export type MutationDonateArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateProfileArgs = {
|
||||
data: InputMaybe<UpdateProfileInput>;
|
||||
export type MutationUpdateProfileDetailsArgs = {
|
||||
data: InputMaybe<ProfileDetailsInput>;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateUserPreferencesArgs = {
|
||||
userKeys: InputMaybe<Array<UserKeyInputType>>;
|
||||
};
|
||||
|
||||
|
||||
@@ -164,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',
|
||||
@@ -193,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>;
|
||||
@@ -224,7 +284,7 @@ export type Query = {
|
||||
getProject: Project;
|
||||
getTrendingPosts: Array<Post>;
|
||||
hottestProjects: Array<Project>;
|
||||
me: Maybe<User>;
|
||||
me: Maybe<MyProfile>;
|
||||
newProjects: Array<Project>;
|
||||
officialTags: Array<Tag>;
|
||||
popularTags: Array<Tag>;
|
||||
@@ -361,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']>;
|
||||
@@ -388,14 +434,17 @@ 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 UserKeyInputType = {
|
||||
key: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
};
|
||||
|
||||
export enum Vote_Item_Type {
|
||||
Bounty = 'Bounty',
|
||||
PostComment = 'PostComment',
|
||||
@@ -416,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; }>;
|
||||
|
||||
|
||||
@@ -436,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; }>;
|
||||
|
||||
@@ -515,19 +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 MyProfilePreferencesQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type MyProfilePreferencesQuery = { __typename?: 'Query', me: { __typename?: 'MyProfile', id: number, nostr_prv_key: string | null, nostr_pub_key: string | null, walletsKeys: Array<{ __typename?: 'WalletKey', key: string, name: string }> } | null };
|
||||
|
||||
export type UpdateUserPreferencesMutationVariables = Exact<{
|
||||
walletsKeys: InputMaybe<Array<UserKeyInputType> | UserKeyInputType>;
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateUserPreferencesMutation = { __typename?: 'Mutation', updateUserPreferences: { __typename?: 'MyProfile', id: number, 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<ProfileDetailsInput>;
|
||||
}>;
|
||||
|
||||
|
||||
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 UpdateProfileAboutMutationVariables = Exact<{
|
||||
data: InputMaybe<UpdateProfileInput>;
|
||||
}>;
|
||||
|
||||
|
||||
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 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'];
|
||||
@@ -698,6 +770,8 @@ export const MeDocument = gql`
|
||||
name
|
||||
avatar
|
||||
join_date
|
||||
jobTitle
|
||||
bio
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -1306,9 +1380,88 @@ 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 ProfileDocument = gql`
|
||||
query profile($profileId: Int!) {
|
||||
profile(id: $profileId) {
|
||||
export const MyProfilePreferencesDocument = gql`
|
||||
query MyProfilePreferences {
|
||||
me {
|
||||
id
|
||||
walletsKeys {
|
||||
key
|
||||
name
|
||||
}
|
||||
nostr_prv_key
|
||||
nostr_pub_key
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useMyProfilePreferencesQuery__
|
||||
*
|
||||
* 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 } = useMyProfilePreferencesQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useMyProfilePreferencesQuery(baseOptions?: Apollo.QueryHookOptions<MyProfilePreferencesQuery, MyProfilePreferencesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<MyProfilePreferencesQuery, MyProfilePreferencesQueryVariables>(MyProfilePreferencesDocument, options);
|
||||
}
|
||||
export function useMyProfilePreferencesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MyProfilePreferencesQuery, MyProfilePreferencesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<MyProfilePreferencesQuery, MyProfilePreferencesQueryVariables>(MyProfilePreferencesDocument, options);
|
||||
}
|
||||
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($walletsKeys: [UserKeyInputType!]) {
|
||||
updateUserPreferences(userKeys: $walletsKeys) {
|
||||
id
|
||||
walletsKeys {
|
||||
key
|
||||
name
|
||||
}
|
||||
nostr_pub_key
|
||||
nostr_prv_key
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type UpdateUserPreferencesMutationFn = Apollo.MutationFunction<UpdateUserPreferencesMutation, UpdateUserPreferencesMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useUpdateUserPreferencesMutation__
|
||||
*
|
||||
* 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 [updateUserPreferencesMutation, { data, loading, error }] = useUpdateUserPreferencesMutation({
|
||||
* variables: {
|
||||
* walletsKeys: // value for 'walletsKeys'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useUpdateUserPreferencesMutation(baseOptions?: Apollo.MutationHookOptions<UpdateUserPreferencesMutation, UpdateUserPreferencesMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<UpdateUserPreferencesMutation, UpdateUserPreferencesMutationVariables>(UpdateUserPreferencesDocument, options);
|
||||
}
|
||||
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
|
||||
@@ -1323,61 +1476,48 @@ export const ProfileDocument = gql`
|
||||
linkedin
|
||||
bio
|
||||
location
|
||||
stories {
|
||||
id
|
||||
title
|
||||
createdAt
|
||||
tags {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
}
|
||||
nostr_prv_key
|
||||
nostr_pub_key
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useProfileQuery__
|
||||
* __useMyProfileAboutQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useProfileQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useProfileQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* 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 } = useProfileQuery({
|
||||
* const { data, loading, error } = useMyProfileAboutQuery({
|
||||
* variables: {
|
||||
* profileId: // value for 'profileId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useProfileQuery(baseOptions: Apollo.QueryHookOptions<ProfileQuery, ProfileQueryVariables>) {
|
||||
export function useMyProfileAboutQuery(baseOptions?: Apollo.QueryHookOptions<MyProfileAboutQuery, MyProfileAboutQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<ProfileQuery, ProfileQueryVariables>(ProfileDocument, options);
|
||||
return Apollo.useQuery<MyProfileAboutQuery, MyProfileAboutQueryVariables>(MyProfileAboutDocument, options);
|
||||
}
|
||||
export function useProfileLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ProfileQuery, ProfileQueryVariables>) {
|
||||
export function useMyProfileAboutLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MyProfileAboutQuery, MyProfileAboutQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<ProfileQuery, ProfileQueryVariables>(ProfileDocument, options);
|
||||
return Apollo.useLazyQuery<MyProfileAboutQuery, MyProfileAboutQueryVariables>(MyProfileAboutDocument, options);
|
||||
}
|
||||
export type ProfileQueryHookResult = ReturnType<typeof useProfileQuery>;
|
||||
export type ProfileLazyQueryHookResult = ReturnType<typeof useProfileLazyQuery>;
|
||||
export type ProfileQueryResult = Apollo.QueryResult<ProfileQuery, ProfileQueryVariables>;
|
||||
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: UpdateProfileInput) {
|
||||
updateProfile(data: $data) {
|
||||
mutation updateProfileAbout($data: ProfileDetailsInput) {
|
||||
updateProfileDetails(data: $data) {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
join_date
|
||||
website
|
||||
role
|
||||
email
|
||||
lightning_address
|
||||
jobTitle
|
||||
lightning_address
|
||||
website
|
||||
twitter
|
||||
github
|
||||
linkedin
|
||||
@@ -1412,6 +1552,64 @@ export function useUpdateProfileAboutMutation(baseOptions?: Apollo.MutationHookO
|
||||
export type UpdateProfileAboutMutationHookResult = ReturnType<typeof useUpdateProfileAboutMutation>;
|
||||
export type UpdateProfileAboutMutationResult = Apollo.MutationResult<UpdateProfileAboutMutation>;
|
||||
export type UpdateProfileAboutMutationOptions = Apollo.BaseMutationOptions<UpdateProfileAboutMutation, UpdateProfileAboutMutationVariables>;
|
||||
export const ProfileDocument = gql`
|
||||
query profile($profileId: Int!) {
|
||||
profile(id: $profileId) {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
join_date
|
||||
role
|
||||
email
|
||||
jobTitle
|
||||
lightning_address
|
||||
website
|
||||
twitter
|
||||
github
|
||||
linkedin
|
||||
bio
|
||||
location
|
||||
stories {
|
||||
id
|
||||
title
|
||||
createdAt
|
||||
tags {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useProfileQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useProfileQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useProfileQuery` 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 } = useProfileQuery({
|
||||
* variables: {
|
||||
* profileId: // value for 'profileId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useProfileQuery(baseOptions: Apollo.QueryHookOptions<ProfileQuery, ProfileQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<ProfileQuery, ProfileQueryVariables>(ProfileDocument, options);
|
||||
}
|
||||
export function useProfileLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ProfileQuery, ProfileQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<ProfileQuery, ProfileQueryVariables>(ProfileDocument, options);
|
||||
}
|
||||
export type ProfileQueryHookResult = ReturnType<typeof useProfileQuery>;
|
||||
export type ProfileLazyQueryHookResult = ReturnType<typeof useProfileLazyQuery>;
|
||||
export type ProfileQueryResult = Apollo.QueryResult<ProfileQuery, ProfileQueryVariables>;
|
||||
export const CategoryPageDocument = gql`
|
||||
query CategoryPage($categoryId: Int!) {
|
||||
projectsByCategory(category_id: $categoryId) {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
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",
|
||||
bio: "Lorem asiop asklh kluiw wekjhl shkj kljhsva klu khsc klhlkbs mjklwqr kmlk sadlfui mewr qiumnk, asdjomi cskhsdf.",
|
||||
name: "123123124asdfsadfsa8d7fsadfasdf",
|
||||
name: "Mtg",
|
||||
github: "MTG2000",
|
||||
jobTitle: "Front-end Web Developer",
|
||||
join_date: new Date(2021).toISOString(),
|
||||
@@ -14,9 +14,19 @@ export const user: User = {
|
||||
linkedin: "https://www.linkedin.com/in/mtg-softwares-dev/",
|
||||
location: "Germany, Berlin",
|
||||
role: "user",
|
||||
twitter: "john-doe",
|
||||
twitter: "mtg",
|
||||
website: "https://mtg-dev.tech",
|
||||
stories: posts.stories,
|
||||
nostr_prv_key: "123123124asdfsadfsa8d7fsadfasdf",
|
||||
nostr_pub_key: "123124123123dfsadfsa8d7f11sadfasdf",
|
||||
walletsKeys: [
|
||||
{
|
||||
key: "1645h234j2421zxvertw",
|
||||
name: "My Alby wallet key"
|
||||
},
|
||||
{
|
||||
key: "6643534534534534543",
|
||||
name: "My Phoenix wallet key"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ import {
|
||||
MeQuery,
|
||||
ProfileQuery,
|
||||
GetMyDraftsQuery,
|
||||
MyProfileAboutQuery,
|
||||
MyProfilePreferencesQuery,
|
||||
} from 'src/graphql'
|
||||
|
||||
const delay = (ms = 1000) => new Promise((res) => setTimeout(res, ms + Math.random() * 1000))
|
||||
@@ -195,6 +197,7 @@ export const handlers = [
|
||||
|
||||
graphql.query<MeQuery>('Me', async (req, res, ctx) => {
|
||||
await delay()
|
||||
console.log("ME");
|
||||
|
||||
return res(
|
||||
ctx.data({
|
||||
@@ -203,6 +206,27 @@ export const handlers = [
|
||||
)
|
||||
}),
|
||||
|
||||
|
||||
graphql.query<MyProfileAboutQuery>('MyProfileAbout', async (req, res, ctx) => {
|
||||
await delay()
|
||||
return res(
|
||||
ctx.data({
|
||||
me: me(),
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
graphql.query<MyProfilePreferencesQuery>('MyProfilePreferences', async (req, res, ctx) => {
|
||||
await delay()
|
||||
return res(
|
||||
ctx.data({
|
||||
me: me(),
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
|
||||
|
||||
graphql.query<ProfileQuery>('profile', async (req, res, ctx) => {
|
||||
await delay()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MOCK_DATA } from "./data";
|
||||
import { Query, QueryGetFeedArgs, QueryGetPostByIdArgs } from 'src/graphql'
|
||||
import { MyProfile, Query, QueryGetFeedArgs, QueryGetPostByIdArgs, User } from 'src/graphql'
|
||||
import { Chance } from "chance";
|
||||
import { tags } from "./data/tags";
|
||||
import { hackathons } from "./data/hackathon";
|
||||
@@ -72,11 +72,16 @@ export function getAllHackathons() {
|
||||
}
|
||||
|
||||
export function me() {
|
||||
return MOCK_DATA['user']
|
||||
return {
|
||||
...MOCK_DATA['user'],
|
||||
__typename: "MyProfile",
|
||||
} as MyProfile
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function profile() {
|
||||
return MOCK_DATA['user']
|
||||
return { ...MOCK_DATA['user'], __typename: 'User' } as User
|
||||
}
|
||||
|
||||
export function getMyDrafts(): Query['getMyDrafts'] {
|
||||
|
||||
@@ -8,7 +8,8 @@ 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 { RemoveWalletKeyModal } from "src/features/Profiles/pages/EditProfilePage/PreferencesTab/RemoveWalletKeyModal";
|
||||
|
||||
import { ComponentProps } from "react";
|
||||
import { generateId } from "src/utils/helperFunctions";
|
||||
@@ -24,19 +25,27 @@ export enum Direction {
|
||||
|
||||
|
||||
export const ALL_MODALS = {
|
||||
//Projects
|
||||
ProjectDetailsCard,
|
||||
|
||||
// Auth
|
||||
Login_ScanningWalletCard,
|
||||
Login_NativeWalletCard,
|
||||
Login_SuccessCard,
|
||||
Login_ExternalWalletCard,
|
||||
VoteCard,
|
||||
Claim_GenerateSignatureCard,
|
||||
Claim_CopySignatureCard,
|
||||
Claim_SubmittedCard,
|
||||
Claim_FundWithdrawCard,
|
||||
|
||||
// Misc
|
||||
ConfirmModal,
|
||||
VoteCard,
|
||||
NoWeblnModal,
|
||||
|
||||
// User Wallets Keys
|
||||
LinkingAccountModal,
|
||||
RemoveWalletKeyModal,
|
||||
|
||||
// Text Editor Modals
|
||||
InsertImageModal,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user