mirror of
https://github.com/aljazceru/landscape-template.git
synced 2026-01-05 07:24:28 +01:00
Merge pull request #129 from peakshift/feature/profile-roles-skills-ui
Feature - Profile Roles & Skills UI + Api
This commit is contained in:
@@ -28,6 +28,13 @@ declare global {
|
||||
}
|
||||
|
||||
export interface NexusGenInputs {
|
||||
MakerRoleInput: { // input type
|
||||
id: number; // Int!
|
||||
level: NexusGenEnums['RoleLevelEnum']; // RoleLevelEnum!
|
||||
}
|
||||
MakerSkillInput: { // input type
|
||||
id: number; // Int!
|
||||
}
|
||||
ProfileDetailsInput: { // input type
|
||||
avatar?: string | null; // String
|
||||
bio?: string | null; // String
|
||||
@@ -41,6 +48,10 @@ export interface NexusGenInputs {
|
||||
twitter?: string | null; // String
|
||||
website?: string | null; // String
|
||||
}
|
||||
ProfileRolesInput: { // input type
|
||||
roles: NexusGenInputs['MakerRoleInput'][]; // [MakerRoleInput!]!
|
||||
skills: NexusGenInputs['MakerSkillInput'][]; // [MakerSkillInput!]!
|
||||
}
|
||||
StoryInputType: { // input type
|
||||
body: string; // String!
|
||||
cover_image?: string | null; // String
|
||||
@@ -57,6 +68,7 @@ export interface NexusGenInputs {
|
||||
|
||||
export interface NexusGenEnums {
|
||||
POST_TYPE: "Bounty" | "Question" | "Story"
|
||||
RoleLevelEnum: 3 | 0 | 1 | 2 | 4
|
||||
VOTE_ITEM_TYPE: "Bounty" | "PostComment" | "Project" | "Question" | "Story" | "User"
|
||||
}
|
||||
|
||||
@@ -124,6 +136,11 @@ export interface NexusGenObjects {
|
||||
prizes: string; // String!
|
||||
touranments: string; // String!
|
||||
}
|
||||
GenericMakerRole: { // root type
|
||||
icon: string; // String!
|
||||
id: number; // Int!
|
||||
title: string; // String!
|
||||
}
|
||||
Hackathon: { // root type
|
||||
cover_image: string; // String!
|
||||
description: string; // String!
|
||||
@@ -140,6 +157,16 @@ export interface NexusGenObjects {
|
||||
metadata?: string | null; // String
|
||||
minSendable?: number | null; // Int
|
||||
}
|
||||
MakerRole: { // root type
|
||||
icon: string; // String!
|
||||
id: number; // Int!
|
||||
level: NexusGenEnums['RoleLevelEnum']; // RoleLevelEnum!
|
||||
title: string; // String!
|
||||
}
|
||||
MakerSkill: { // root type
|
||||
id: number; // Int!
|
||||
title: string; // String!
|
||||
}
|
||||
Mutation: {};
|
||||
MyProfile: { // root type
|
||||
avatar: string; // String!
|
||||
@@ -208,6 +235,16 @@ export interface NexusGenObjects {
|
||||
isOfficial?: boolean | null; // Boolean
|
||||
title: string; // String!
|
||||
}
|
||||
Tournament: { // root type
|
||||
cover_image: string; // String!
|
||||
description: string; // String!
|
||||
end_date: NexusGenScalars['Date']; // Date!
|
||||
id: number; // Int!
|
||||
start_date: NexusGenScalars['Date']; // Date!
|
||||
thumbnail_image: string; // String!
|
||||
title: string; // String!
|
||||
website: string; // String!
|
||||
}
|
||||
User: { // root type
|
||||
avatar: string; // String!
|
||||
bio?: string | null; // String
|
||||
@@ -315,6 +352,11 @@ export interface NexusGenFieldTypes {
|
||||
prizes: string; // String!
|
||||
touranments: string; // String!
|
||||
}
|
||||
GenericMakerRole: { // field return type
|
||||
icon: string; // String!
|
||||
id: number; // Int!
|
||||
title: string; // String!
|
||||
}
|
||||
Hackathon: { // field return type
|
||||
cover_image: string; // String!
|
||||
description: string; // String!
|
||||
@@ -332,6 +374,16 @@ export interface NexusGenFieldTypes {
|
||||
metadata: string | null; // String
|
||||
minSendable: number | null; // Int
|
||||
}
|
||||
MakerRole: { // field return type
|
||||
icon: string; // String!
|
||||
id: number; // Int!
|
||||
level: NexusGenEnums['RoleLevelEnum']; // RoleLevelEnum!
|
||||
title: string; // String!
|
||||
}
|
||||
MakerSkill: { // field return type
|
||||
id: number; // Int!
|
||||
title: string; // String!
|
||||
}
|
||||
Mutation: { // field return type
|
||||
confirmDonation: NexusGenRootTypes['Donation']; // Donation!
|
||||
confirmVote: NexusGenRootTypes['Vote']; // Vote!
|
||||
@@ -339,6 +391,7 @@ export interface NexusGenFieldTypes {
|
||||
deleteStory: NexusGenRootTypes['Story'] | null; // Story
|
||||
donate: NexusGenRootTypes['Donation']; // Donation!
|
||||
updateProfileDetails: NexusGenRootTypes['MyProfile'] | null; // MyProfile
|
||||
updateProfileRoles: NexusGenRootTypes['MyProfile'] | null; // MyProfile
|
||||
updateUserPreferences: NexusGenRootTypes['MyProfile']; // MyProfile!
|
||||
vote: NexusGenRootTypes['Vote']; // Vote!
|
||||
}
|
||||
@@ -357,7 +410,11 @@ export interface NexusGenFieldTypes {
|
||||
nostr_prv_key: string | null; // String
|
||||
nostr_pub_key: string | null; // String
|
||||
role: string | null; // String
|
||||
roles: NexusGenRootTypes['MakerRole'][]; // [MakerRole!]!
|
||||
similar_makers: NexusGenRootTypes['User'][]; // [User!]!
|
||||
skills: NexusGenRootTypes['MakerSkill'][]; // [MakerSkill!]!
|
||||
stories: NexusGenRootTypes['Story'][]; // [Story!]!
|
||||
tournaments: NexusGenRootTypes['Tournament'][]; // [Tournament!]!
|
||||
twitter: string | null; // String
|
||||
walletsKeys: NexusGenRootTypes['WalletKey'][]; // [WalletKey!]!
|
||||
website: string | null; // String
|
||||
@@ -389,6 +446,8 @@ export interface NexusGenFieldTypes {
|
||||
allCategories: NexusGenRootTypes['Category'][]; // [Category!]!
|
||||
allProjects: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
getAllHackathons: NexusGenRootTypes['Hackathon'][]; // [Hackathon!]!
|
||||
getAllMakersRoles: NexusGenRootTypes['GenericMakerRole'][]; // [GenericMakerRole!]!
|
||||
getAllMakersSkills: NexusGenRootTypes['MakerSkill'][]; // [MakerSkill!]!
|
||||
getCategory: NexusGenRootTypes['Category']; // Category!
|
||||
getDonationsStats: NexusGenRootTypes['DonationsStats']; // DonationsStats!
|
||||
getFeed: NexusGenRootTypes['Post'][]; // [Post!]!
|
||||
@@ -405,6 +464,7 @@ export interface NexusGenFieldTypes {
|
||||
profile: NexusGenRootTypes['User'] | null; // User
|
||||
projectsByCategory: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
searchProjects: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
similarMakers: NexusGenRootTypes['User'][]; // [User!]!
|
||||
}
|
||||
Question: { // field return type
|
||||
author: NexusGenRootTypes['Author']; // Author!
|
||||
@@ -442,6 +502,17 @@ export interface NexusGenFieldTypes {
|
||||
isOfficial: boolean | null; // Boolean
|
||||
title: string; // String!
|
||||
}
|
||||
Tournament: { // field return type
|
||||
cover_image: string; // String!
|
||||
description: string; // String!
|
||||
end_date: NexusGenScalars['Date']; // Date!
|
||||
id: number; // Int!
|
||||
start_date: NexusGenScalars['Date']; // Date!
|
||||
tags: NexusGenRootTypes['Tag'][]; // [Tag!]!
|
||||
thumbnail_image: string; // String!
|
||||
title: string; // String!
|
||||
website: string; // String!
|
||||
}
|
||||
User: { // field return type
|
||||
avatar: string; // String!
|
||||
bio: string | null; // String
|
||||
@@ -455,7 +526,11 @@ export interface NexusGenFieldTypes {
|
||||
location: string | null; // String
|
||||
name: string; // String!
|
||||
role: string | null; // String
|
||||
roles: NexusGenRootTypes['MakerRole'][]; // [MakerRole!]!
|
||||
similar_makers: NexusGenRootTypes['User'][]; // [User!]!
|
||||
skills: NexusGenRootTypes['MakerSkill'][]; // [MakerSkill!]!
|
||||
stories: NexusGenRootTypes['Story'][]; // [Story!]!
|
||||
tournaments: NexusGenRootTypes['Tournament'][]; // [Tournament!]!
|
||||
twitter: string | null; // String
|
||||
website: string | null; // String
|
||||
}
|
||||
@@ -485,7 +560,11 @@ export interface NexusGenFieldTypes {
|
||||
location: string | null; // String
|
||||
name: string; // String!
|
||||
role: string | null; // String
|
||||
roles: NexusGenRootTypes['MakerRole'][]; // [MakerRole!]!
|
||||
similar_makers: NexusGenRootTypes['User'][]; // [User!]!
|
||||
skills: NexusGenRootTypes['MakerSkill'][]; // [MakerSkill!]!
|
||||
stories: NexusGenRootTypes['Story'][]; // [Story!]!
|
||||
tournaments: NexusGenRootTypes['Tournament'][]; // [Tournament!]!
|
||||
twitter: string | null; // String
|
||||
website: string | null; // String
|
||||
}
|
||||
@@ -564,6 +643,11 @@ export interface NexusGenFieldTypeNames {
|
||||
prizes: 'String'
|
||||
touranments: 'String'
|
||||
}
|
||||
GenericMakerRole: { // field return type name
|
||||
icon: 'String'
|
||||
id: 'Int'
|
||||
title: 'String'
|
||||
}
|
||||
Hackathon: { // field return type name
|
||||
cover_image: 'String'
|
||||
description: 'String'
|
||||
@@ -581,6 +665,16 @@ export interface NexusGenFieldTypeNames {
|
||||
metadata: 'String'
|
||||
minSendable: 'Int'
|
||||
}
|
||||
MakerRole: { // field return type name
|
||||
icon: 'String'
|
||||
id: 'Int'
|
||||
level: 'RoleLevelEnum'
|
||||
title: 'String'
|
||||
}
|
||||
MakerSkill: { // field return type name
|
||||
id: 'Int'
|
||||
title: 'String'
|
||||
}
|
||||
Mutation: { // field return type name
|
||||
confirmDonation: 'Donation'
|
||||
confirmVote: 'Vote'
|
||||
@@ -588,6 +682,7 @@ export interface NexusGenFieldTypeNames {
|
||||
deleteStory: 'Story'
|
||||
donate: 'Donation'
|
||||
updateProfileDetails: 'MyProfile'
|
||||
updateProfileRoles: 'MyProfile'
|
||||
updateUserPreferences: 'MyProfile'
|
||||
vote: 'Vote'
|
||||
}
|
||||
@@ -606,7 +701,11 @@ export interface NexusGenFieldTypeNames {
|
||||
nostr_prv_key: 'String'
|
||||
nostr_pub_key: 'String'
|
||||
role: 'String'
|
||||
roles: 'MakerRole'
|
||||
similar_makers: 'User'
|
||||
skills: 'MakerSkill'
|
||||
stories: 'Story'
|
||||
tournaments: 'Tournament'
|
||||
twitter: 'String'
|
||||
walletsKeys: 'WalletKey'
|
||||
website: 'String'
|
||||
@@ -638,6 +737,8 @@ export interface NexusGenFieldTypeNames {
|
||||
allCategories: 'Category'
|
||||
allProjects: 'Project'
|
||||
getAllHackathons: 'Hackathon'
|
||||
getAllMakersRoles: 'GenericMakerRole'
|
||||
getAllMakersSkills: 'MakerSkill'
|
||||
getCategory: 'Category'
|
||||
getDonationsStats: 'DonationsStats'
|
||||
getFeed: 'Post'
|
||||
@@ -654,6 +755,7 @@ export interface NexusGenFieldTypeNames {
|
||||
profile: 'User'
|
||||
projectsByCategory: 'Project'
|
||||
searchProjects: 'Project'
|
||||
similarMakers: 'User'
|
||||
}
|
||||
Question: { // field return type name
|
||||
author: 'Author'
|
||||
@@ -691,6 +793,17 @@ export interface NexusGenFieldTypeNames {
|
||||
isOfficial: 'Boolean'
|
||||
title: 'String'
|
||||
}
|
||||
Tournament: { // field return type name
|
||||
cover_image: 'String'
|
||||
description: 'String'
|
||||
end_date: 'Date'
|
||||
id: 'Int'
|
||||
start_date: 'Date'
|
||||
tags: 'Tag'
|
||||
thumbnail_image: 'String'
|
||||
title: 'String'
|
||||
website: 'String'
|
||||
}
|
||||
User: { // field return type name
|
||||
avatar: 'String'
|
||||
bio: 'String'
|
||||
@@ -704,7 +817,11 @@ export interface NexusGenFieldTypeNames {
|
||||
location: 'String'
|
||||
name: 'String'
|
||||
role: 'String'
|
||||
roles: 'MakerRole'
|
||||
similar_makers: 'User'
|
||||
skills: 'MakerSkill'
|
||||
stories: 'Story'
|
||||
tournaments: 'Tournament'
|
||||
twitter: 'String'
|
||||
website: 'String'
|
||||
}
|
||||
@@ -734,7 +851,11 @@ export interface NexusGenFieldTypeNames {
|
||||
location: 'String'
|
||||
name: 'String'
|
||||
role: 'String'
|
||||
roles: 'MakerRole'
|
||||
similar_makers: 'User'
|
||||
skills: 'MakerSkill'
|
||||
stories: 'Story'
|
||||
tournaments: 'Tournament'
|
||||
twitter: 'String'
|
||||
website: 'String'
|
||||
}
|
||||
@@ -772,6 +893,9 @@ export interface NexusGenArgTypes {
|
||||
updateProfileDetails: { // args
|
||||
data?: NexusGenInputs['ProfileDetailsInput'] | null; // ProfileDetailsInput
|
||||
}
|
||||
updateProfileRoles: { // args
|
||||
data?: NexusGenInputs['ProfileRolesInput'] | null; // ProfileRolesInput
|
||||
}
|
||||
updateUserPreferences: { // args
|
||||
userKeys?: NexusGenInputs['UserKeyInputType'][] | null; // [UserKeyInputType!]
|
||||
}
|
||||
@@ -833,6 +957,9 @@ export interface NexusGenArgTypes {
|
||||
skip?: number | null; // Int
|
||||
take: number | null; // Int
|
||||
}
|
||||
similarMakers: { // args
|
||||
id: number; // Int!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,11 @@ interface BaseUser {
|
||||
location: String
|
||||
name: String!
|
||||
role: String
|
||||
roles: [MakerRole!]!
|
||||
similar_makers: [User!]!
|
||||
skills: [MakerSkill!]!
|
||||
stories: [Story!]!
|
||||
tournaments: [Tournament!]!
|
||||
twitter: String
|
||||
website: String
|
||||
}
|
||||
@@ -92,6 +96,12 @@ type DonationsStats {
|
||||
touranments: String!
|
||||
}
|
||||
|
||||
type GenericMakerRole {
|
||||
icon: String!
|
||||
id: Int!
|
||||
title: String!
|
||||
}
|
||||
|
||||
type Hackathon {
|
||||
cover_image: String!
|
||||
description: String!
|
||||
@@ -111,6 +121,27 @@ type LnurlDetails {
|
||||
minSendable: Int
|
||||
}
|
||||
|
||||
type MakerRole {
|
||||
icon: String!
|
||||
id: Int!
|
||||
level: RoleLevelEnum!
|
||||
title: String!
|
||||
}
|
||||
|
||||
input MakerRoleInput {
|
||||
id: Int!
|
||||
level: RoleLevelEnum!
|
||||
}
|
||||
|
||||
type MakerSkill {
|
||||
id: Int!
|
||||
title: String!
|
||||
}
|
||||
|
||||
input MakerSkillInput {
|
||||
id: Int!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
confirmDonation(payment_request: String!, preimage: String!): Donation!
|
||||
confirmVote(payment_request: String!, preimage: String!): Vote!
|
||||
@@ -118,6 +149,7 @@ type Mutation {
|
||||
deleteStory(id: Int!): Story
|
||||
donate(amount_in_sat: Int!): Donation!
|
||||
updateProfileDetails(data: ProfileDetailsInput): MyProfile
|
||||
updateProfileRoles(data: ProfileRolesInput): MyProfile
|
||||
updateUserPreferences(userKeys: [UserKeyInputType!]): MyProfile!
|
||||
vote(amount_in_sat: Int!, item_id: Int!, item_type: VOTE_ITEM_TYPE!): Vote!
|
||||
}
|
||||
@@ -137,7 +169,11 @@ type MyProfile implements BaseUser {
|
||||
nostr_prv_key: String
|
||||
nostr_pub_key: String
|
||||
role: String
|
||||
roles: [MakerRole!]!
|
||||
similar_makers: [User!]!
|
||||
skills: [MakerSkill!]!
|
||||
stories: [Story!]!
|
||||
tournaments: [Tournament!]!
|
||||
twitter: String
|
||||
walletsKeys: [WalletKey!]!
|
||||
website: String
|
||||
@@ -185,6 +221,11 @@ input ProfileDetailsInput {
|
||||
website: String
|
||||
}
|
||||
|
||||
input ProfileRolesInput {
|
||||
roles: [MakerRoleInput!]!
|
||||
skills: [MakerSkillInput!]!
|
||||
}
|
||||
|
||||
type Project {
|
||||
awards: [Award!]!
|
||||
category: Category!
|
||||
@@ -205,6 +246,8 @@ type Query {
|
||||
allCategories: [Category!]!
|
||||
allProjects(skip: Int = 0, take: Int = 50): [Project!]!
|
||||
getAllHackathons(sortBy: String, tag: Int): [Hackathon!]!
|
||||
getAllMakersRoles: [GenericMakerRole!]!
|
||||
getAllMakersSkills: [MakerSkill!]!
|
||||
getCategory(id: Int!): Category!
|
||||
getDonationsStats: DonationsStats!
|
||||
getFeed(skip: Int = 0, sortBy: String, tag: Int = 0, take: Int = 10): [Post!]!
|
||||
@@ -221,6 +264,7 @@ type Query {
|
||||
profile(id: Int!): User
|
||||
projectsByCategory(category_id: Int!, skip: Int = 0, take: Int = 10): [Project!]!
|
||||
searchProjects(search: String!, skip: Int = 0, take: Int = 50): [Project!]!
|
||||
similarMakers(id: Int!): [User!]!
|
||||
}
|
||||
|
||||
type Question implements PostBase {
|
||||
@@ -237,6 +281,14 @@ type Question implements PostBase {
|
||||
votes_count: Int!
|
||||
}
|
||||
|
||||
enum RoleLevelEnum {
|
||||
Advanced
|
||||
Beginner
|
||||
Hobbyist
|
||||
Intermediate
|
||||
Pro
|
||||
}
|
||||
|
||||
type Story implements PostBase {
|
||||
author: Author!
|
||||
body: String!
|
||||
@@ -271,6 +323,18 @@ type Tag {
|
||||
title: String!
|
||||
}
|
||||
|
||||
type Tournament {
|
||||
cover_image: String!
|
||||
description: String!
|
||||
end_date: Date!
|
||||
id: Int!
|
||||
start_date: Date!
|
||||
tags: [Tag!]!
|
||||
thumbnail_image: String!
|
||||
title: String!
|
||||
website: String!
|
||||
}
|
||||
|
||||
type User implements BaseUser {
|
||||
avatar: String!
|
||||
bio: String
|
||||
@@ -284,7 +348,11 @@ type User implements BaseUser {
|
||||
location: String
|
||||
name: String!
|
||||
role: String
|
||||
roles: [MakerRole!]!
|
||||
similar_makers: [User!]!
|
||||
skills: [MakerSkill!]!
|
||||
stories: [Story!]!
|
||||
tournaments: [Tournament!]!
|
||||
twitter: String
|
||||
website: String
|
||||
}
|
||||
|
||||
55
api/functions/graphql/types/tournaments.js
Normal file
55
api/functions/graphql/types/tournaments.js
Normal file
@@ -0,0 +1,55 @@
|
||||
const {
|
||||
intArg,
|
||||
objectType,
|
||||
stringArg,
|
||||
extendType,
|
||||
nonNull,
|
||||
} = require('nexus');
|
||||
const { prisma } = require('../../../prisma');
|
||||
|
||||
|
||||
|
||||
const Tournament = objectType({
|
||||
name: 'Tournament',
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
t.nonNull.string('title');
|
||||
t.nonNull.string('description');
|
||||
t.nonNull.string('thumbnail_image');
|
||||
t.nonNull.string('cover_image');
|
||||
t.nonNull.date('start_date');
|
||||
t.nonNull.date('end_date');
|
||||
t.nonNull.string('website');
|
||||
t.nonNull.list.nonNull.field('tags', {
|
||||
type: "Tag",
|
||||
resolve: (parent) => {
|
||||
// return prisma.hackathon.findUnique({ where: { id: parent.id } }).tags();
|
||||
return [];
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
const getAllTournaments = extendType({
|
||||
type: "Query",
|
||||
definition(t) {
|
||||
t.nonNull.list.nonNull.field('getAllTournaments', {
|
||||
type: Tournament,
|
||||
args: {
|
||||
sortBy: stringArg(),
|
||||
tag: intArg(),
|
||||
},
|
||||
resolve(_, args) {
|
||||
const { sortBy, tag } = args;
|
||||
return [];
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
// Types
|
||||
Tournament,
|
||||
// Queries
|
||||
getAllTournaments,
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
|
||||
const { prisma } = require('../../../prisma');
|
||||
const { objectType, extendType, intArg, nonNull, inputObjectType, interfaceType, list } = require("nexus");
|
||||
const { objectType, extendType, intArg, nonNull, inputObjectType, interfaceType, list, enumType } = require("nexus");
|
||||
const { getUserByPubKey } = require("../../../auth/utils/helperFuncs");
|
||||
const { removeNulls } = require("./helpers");
|
||||
const { Tournament } = require('./tournaments');
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +25,54 @@ const BaseUser = interfaceType({
|
||||
t.string('linkedin')
|
||||
t.string('bio')
|
||||
t.string('location')
|
||||
t.nonNull.list.nonNull.field('roles', {
|
||||
type: MakerRole,
|
||||
resolve: async (parent) => {
|
||||
const data = await prisma.user.findUnique({
|
||||
where: {
|
||||
id: parent.id
|
||||
},
|
||||
select: {
|
||||
roles: {
|
||||
select: {
|
||||
role: true,
|
||||
level: true
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
return data.roles.map(data => {
|
||||
return ({ ...data.role, level: data.level })
|
||||
})
|
||||
}
|
||||
})
|
||||
t.nonNull.list.nonNull.field('skills', {
|
||||
type: MakerSkill,
|
||||
resolve: (parent) => {
|
||||
return prisma.user.findUnique({ where: { id: parent.id } }).skills();
|
||||
}
|
||||
})
|
||||
t.nonNull.list.nonNull.field('tournaments', {
|
||||
type: Tournament,
|
||||
resolve: (parent) => {
|
||||
return []
|
||||
}
|
||||
})
|
||||
t.nonNull.list.nonNull.field('similar_makers', {
|
||||
type: "User",
|
||||
resolve(parent,) {
|
||||
return prisma.user.findMany({
|
||||
where: {
|
||||
AND: {
|
||||
id: {
|
||||
not: parent.id
|
||||
}
|
||||
}
|
||||
},
|
||||
take: 3,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
t.nonNull.list.nonNull.field('stories', {
|
||||
@@ -40,6 +89,72 @@ const BaseUser = interfaceType({
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
|
||||
const RoleLevelEnum = enumType({
|
||||
name: 'RoleLevelEnum',
|
||||
members: {
|
||||
Beginner: 0,
|
||||
Hobbyist: 1,
|
||||
Intermediate: 2,
|
||||
Advanced: 3,
|
||||
Pro: 4,
|
||||
},
|
||||
});
|
||||
|
||||
const GenericMakerRole = objectType({
|
||||
name: 'GenericMakerRole',
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
t.nonNull.string('title');
|
||||
t.nonNull.string('icon');
|
||||
}
|
||||
})
|
||||
|
||||
const MakerRole = objectType({
|
||||
name: 'MakerRole',
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
t.nonNull.string('title');
|
||||
t.nonNull.string('icon');
|
||||
t.nonNull.field('level', { type: RoleLevelEnum })
|
||||
}
|
||||
})
|
||||
|
||||
const getAllMakersRoles = extendType({
|
||||
type: "Query",
|
||||
definition(t) {
|
||||
t.nonNull.list.nonNull.field('getAllMakersRoles', {
|
||||
type: GenericMakerRole,
|
||||
async resolve(parent, args, context) {
|
||||
return prisma.workRole.findMany();
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const MakerSkill = objectType({
|
||||
name: 'MakerSkill',
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
t.nonNull.string('title');
|
||||
}
|
||||
})
|
||||
|
||||
const getAllMakersSkills = extendType({
|
||||
type: "Query",
|
||||
definition(t) {
|
||||
t.nonNull.list.nonNull.field('getAllMakersSkills', {
|
||||
type: MakerSkill,
|
||||
async resolve(parent, args, context) {
|
||||
return prisma.skill.findMany();
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const User = objectType({
|
||||
name: 'User',
|
||||
definition(t) {
|
||||
@@ -93,6 +208,30 @@ const profile = extendType({
|
||||
}
|
||||
})
|
||||
|
||||
const similarMakers = extendType({
|
||||
type: "Query",
|
||||
definition(t) {
|
||||
t.nonNull.list.nonNull.field('similarMakers', {
|
||||
type: "User",
|
||||
args: {
|
||||
id: nonNull(intArg())
|
||||
},
|
||||
async resolve(parent, { id }, ctx) {
|
||||
return prisma.user.findMany({
|
||||
where: {
|
||||
AND: {
|
||||
id: {
|
||||
not: id
|
||||
}
|
||||
}
|
||||
},
|
||||
take: 3,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const ProfileDetailsInput = inputObjectType({
|
||||
name: 'ProfileDetailsInput',
|
||||
definition(t) {
|
||||
@@ -225,9 +364,88 @@ const updateUserPreferences = extendType({
|
||||
|
||||
|
||||
|
||||
const MakerRoleInput = inputObjectType({
|
||||
name: "MakerRoleInput",
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
t.nonNull.field('level', { type: RoleLevelEnum })
|
||||
}
|
||||
})
|
||||
|
||||
const MakerSkillInput = inputObjectType({
|
||||
name: "MakerSkillInput",
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const ProfileRolesInput = inputObjectType({
|
||||
name: 'ProfileRolesInput',
|
||||
definition(t) {
|
||||
t.nonNull.list.nonNull.field('roles', {
|
||||
type: MakerRoleInput,
|
||||
})
|
||||
t.nonNull.list.nonNull.field('skills', {
|
||||
type: MakerSkillInput,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const updateProfileRoles = extendType({
|
||||
type: 'Mutation',
|
||||
definition(t) {
|
||||
t.field('updateProfileRoles', {
|
||||
type: 'MyProfile',
|
||||
args: { data: ProfileRolesInput },
|
||||
async resolve(_root, args, ctx) {
|
||||
const user = await getUserByPubKey(ctx.userPubKey);
|
||||
|
||||
// Do some validation
|
||||
if (!user)
|
||||
throw new Error("You have to login");
|
||||
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id: user.id,
|
||||
},
|
||||
data: {
|
||||
skills: {
|
||||
set: [],
|
||||
},
|
||||
roles: {
|
||||
deleteMany: {}
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
return prisma.user.update({
|
||||
where: {
|
||||
id: user.id,
|
||||
},
|
||||
data: {
|
||||
skills: {
|
||||
connect: args.data.skills,
|
||||
},
|
||||
roles: {
|
||||
create: args.data.roles.map(r => ({ roleId: r.id, level: r.level }))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = {
|
||||
// Types
|
||||
|
||||
BaseUser,
|
||||
User,
|
||||
MyProfile,
|
||||
@@ -235,7 +453,11 @@ module.exports = {
|
||||
// Queries
|
||||
me,
|
||||
profile,
|
||||
similarMakers,
|
||||
getAllMakersRoles,
|
||||
getAllMakersSkills,
|
||||
// Mutations
|
||||
updateProfileDetails,
|
||||
updateUserPreferences,
|
||||
updateProfileRoles,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "UserKey" ALTER COLUMN "name" SET DEFAULT E'My new wallet key';
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "UsersOnWorkRoles" (
|
||||
"userId" INTEGER NOT NULL,
|
||||
"roleId" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "UsersOnWorkRoles_pkey" PRIMARY KEY ("userId","roleId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "WorkRole" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"icon" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "WorkRole_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Skill" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "Skill_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_SkillToUser" (
|
||||
"A" INTEGER NOT NULL,
|
||||
"B" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "WorkRole_title_key" ON "WorkRole"("title");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Skill_title_key" ON "Skill"("title");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "_SkillToUser_AB_unique" ON "_SkillToUser"("A", "B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_SkillToUser_B_index" ON "_SkillToUser"("B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "UsersOnWorkRoles" ADD CONSTRAINT "UsersOnWorkRoles_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "UsersOnWorkRoles" ADD CONSTRAINT "UsersOnWorkRoles_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "WorkRole"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_SkillToUser" ADD FOREIGN KEY ("A") REFERENCES "Skill"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_SkillToUser" ADD FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `level` to the `UsersOnWorkRoles` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "UsersOnWorkRoles" ADD COLUMN "level" TEXT NOT NULL;
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Changed the type of `level` on the `UsersOnWorkRoles` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "UsersOnWorkRoles" DROP COLUMN "level",
|
||||
ADD COLUMN "level" INTEGER NOT NULL;
|
||||
@@ -65,6 +65,8 @@ model User {
|
||||
posts_comments PostComment[]
|
||||
donations Donation[]
|
||||
userKeys UserKey[]
|
||||
skills Skill[]
|
||||
roles UsersOnWorkRoles[]
|
||||
}
|
||||
|
||||
model UserKey {
|
||||
@@ -75,6 +77,31 @@ model UserKey {
|
||||
user_id Int?
|
||||
}
|
||||
|
||||
model UsersOnWorkRoles {
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
role WorkRole @relation(fields: [roleId], references: [id])
|
||||
roleId Int
|
||||
|
||||
level Int
|
||||
|
||||
@@id([userId, roleId])
|
||||
}
|
||||
|
||||
model WorkRole {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @unique
|
||||
icon String
|
||||
users UsersOnWorkRoles[]
|
||||
}
|
||||
|
||||
model Skill {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @unique
|
||||
|
||||
users User[]
|
||||
}
|
||||
|
||||
// -----------------
|
||||
// Projects
|
||||
// -----------------
|
||||
|
||||
@@ -418,10 +418,103 @@ const hackathons = [
|
||||
},
|
||||
]
|
||||
|
||||
const roles = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Frontend Dev",
|
||||
icon: "💄"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Backend Dev",
|
||||
icon: "💻️"
|
||||
}, {
|
||||
id: 3,
|
||||
title: "UI/UX Designer",
|
||||
icon: "🌈️️"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "Community Manager",
|
||||
icon: "🎉️️"
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "Founder",
|
||||
icon: "🦄️"
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: "Marketer",
|
||||
icon: "🚨️"
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
title: "Content Creator",
|
||||
icon: "🎥️"
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
title: "Researcher",
|
||||
icon: "🔬"
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
title: "Data engineer",
|
||||
icon: "💿️"
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
title: "Growth hacker",
|
||||
icon: "📉️"
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
title: "Technical Writer",
|
||||
icon: "✍️️"
|
||||
},
|
||||
]
|
||||
|
||||
const skills = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Figma"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Prototyping"
|
||||
}, {
|
||||
id: 3,
|
||||
title: "Writing"
|
||||
}, {
|
||||
id: 4,
|
||||
title: "CSS"
|
||||
}, {
|
||||
id: 5,
|
||||
title: "React.js"
|
||||
}, {
|
||||
id: 6,
|
||||
title: "Wordpress"
|
||||
}, {
|
||||
id: 7,
|
||||
title: "Principle app"
|
||||
}, {
|
||||
id: 8,
|
||||
title: "UX design"
|
||||
}, {
|
||||
id: 9,
|
||||
title: "User research"
|
||||
}, {
|
||||
id: 10,
|
||||
title: "User testing"
|
||||
},
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
categories,
|
||||
projects,
|
||||
tags,
|
||||
hackathons,
|
||||
roles,
|
||||
skills,
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
const { generatePrivateKey, getPublicKey } = require("../../api/utils/nostr-tools");
|
||||
const { categories, projects, tags, hackathons } = require("./data");
|
||||
const { categories, projects, tags, hackathons, roles, skills } = require("./data");
|
||||
const Chance = require('chance');
|
||||
const { getCoverImage, randomItems, random } = require("./helpers");
|
||||
|
||||
@@ -58,7 +58,11 @@ async function main() {
|
||||
|
||||
// await createHackathons();
|
||||
|
||||
await fillUserKeysTable()
|
||||
// await fillUserKeysTable()
|
||||
|
||||
// await createRoles();
|
||||
|
||||
// await createSkills();
|
||||
|
||||
}
|
||||
|
||||
@@ -169,6 +173,26 @@ async function fillUserKeysTable() {
|
||||
})
|
||||
}
|
||||
|
||||
async function createRoles() {
|
||||
console.log("Creating Users Roles");
|
||||
await prisma.workRole.createMany({
|
||||
data: roles.map(item => ({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
icon: item.icon,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
async function createSkills() {
|
||||
console.log("Creating Users Skills");
|
||||
await prisma.skill.createMany({
|
||||
data: skills.map(item => ({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
main()
|
||||
|
||||
@@ -14,7 +14,7 @@ export default function TrendingCard() {
|
||||
|
||||
return (
|
||||
<Card onlyMd>
|
||||
<h3 className="text-body2 font-bolder mb-16">Trending on BOLT.FUN</h3>
|
||||
<h3 className="text-body2 font-bolder mb-16">Trending on BOLT🔩FUN</h3>
|
||||
<ul className='flex flex-col'>
|
||||
{
|
||||
trendingPosts.loading ?
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Card from 'src/Components/Card/Card';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
|
||||
export default function UpdateProfileAboutTabSkeleton() {
|
||||
export default function BasicProfileInfoTabSkeleton() {
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-24">
|
||||
<div className="col-span-2 flex flex-col gap-24">
|
||||
@@ -1,6 +1,5 @@
|
||||
import { SubmitHandler, useForm } from "react-hook-form"
|
||||
import Button from "src/Components/Button/Button";
|
||||
import { User, useUpdateProfileAboutMutation, useMyProfileAboutQuery, UpdateProfileAboutMutationVariables } from "src/graphql";
|
||||
import { useUpdateProfileAboutMutation, useMyProfileAboutQuery, UpdateProfileAboutMutationVariables, UserBasicInfoFragmentDoc } from "src/graphql";
|
||||
import { NotificationsService } from "src/services/notifications.service";
|
||||
import * as yup from "yup";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
@@ -9,10 +8,10 @@ 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";
|
||||
import UpdateProfileAboutTabSkeleton from "./BasicProfileInfoTab.Skeleton";
|
||||
import { useApolloClient } from "@apollo/client";
|
||||
|
||||
interface Props {
|
||||
}
|
||||
@@ -53,7 +52,7 @@ const schema: yup.SchemaOf<IFormInputs> = yup.object({
|
||||
|
||||
}).required();
|
||||
|
||||
export default function UpdateMyProfileTab() {
|
||||
export default function BasicProfileInfoTab() {
|
||||
|
||||
const { register, formState: { errors, isDirty, }, handleSubmit, reset } = useForm<IFormInputs>({
|
||||
defaultValues: {},
|
||||
@@ -61,7 +60,7 @@ export default function UpdateMyProfileTab() {
|
||||
mode: 'onBlur',
|
||||
});
|
||||
|
||||
|
||||
const apolloClient = useApolloClient()
|
||||
const profileQuery = useMyProfileAboutQuery({
|
||||
onCompleted: data => {
|
||||
if (data.me)
|
||||
@@ -70,6 +69,7 @@ export default function UpdateMyProfileTab() {
|
||||
})
|
||||
const [mutate, mutationStatus] = useUpdateProfileAboutMutation();
|
||||
|
||||
|
||||
const dispatch = useAppDispatch()
|
||||
usePrompt('You may have some unsaved changes. You still want to leave?', isDirty)
|
||||
|
||||
@@ -106,6 +106,11 @@ export default function UpdateMyProfileTab() {
|
||||
if (data) {
|
||||
dispatch(setUser(data))
|
||||
reset(data);
|
||||
apolloClient.writeFragment({
|
||||
id: `User:${data?.id}`,
|
||||
data,
|
||||
fragment: UserBasicInfoFragmentDoc,
|
||||
})
|
||||
toast.update(toastId, { render: "Saved changes successfully", type: "success", ...NotificationsService.defaultOptions, isLoading: false });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
fragment UserBasicInfo on BaseUser {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
join_date
|
||||
role
|
||||
email
|
||||
jobTitle
|
||||
lightning_address
|
||||
website
|
||||
twitter
|
||||
github
|
||||
linkedin
|
||||
bio
|
||||
location
|
||||
}
|
||||
|
||||
query MyProfileAbout {
|
||||
me {
|
||||
...UserBasicInfo
|
||||
}
|
||||
}
|
||||
|
||||
mutation updateProfileAbout($data: ProfileDetailsInput) {
|
||||
updateProfileDetails(data: $data) {
|
||||
...UserBasicInfo
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,23 @@ import { Navigate, NavLink, Route, Routes } from "react-router-dom";
|
||||
import LoadingPage from "src/Components/LoadingPage/LoadingPage";
|
||||
import NotFoundPage from "src/features/Shared/pages/NotFoundPage/NotFoundPage";
|
||||
import Slider from "src/Components/Slider/Slider";
|
||||
import { useProfileQuery } from "src/graphql";
|
||||
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 PreferencesTab from "./PreferencesTab/PreferencesTab";
|
||||
import RolesSkillsTab from "./RolesSkillsTab/RolesSkillsTab";
|
||||
import Card from "src/Components/Card/Card";
|
||||
import BasicProfileInfoTab from "./BasicProfileInfoTab/BasicProfileInfoTab";
|
||||
|
||||
|
||||
const links = [
|
||||
{
|
||||
text: "👾 My Profile",
|
||||
path: 'my-profile',
|
||||
text: "🤠 Basic information",
|
||||
path: 'basic-info',
|
||||
},
|
||||
{
|
||||
text: "🎛️ Roles & Skills",
|
||||
path: 'roles-skills',
|
||||
},
|
||||
{
|
||||
text: "⚙️ Settings & Preferences",
|
||||
@@ -83,8 +87,9 @@ export default function EditProfilePage() {
|
||||
</aside>
|
||||
<main className="md:col-span-3">
|
||||
<Routes>
|
||||
<Route index element={<Navigate to='my-profile' />} />
|
||||
<Route path='my-profile' element={<UpdateMyProfileTab />} />
|
||||
<Route index element={<Navigate to='basic-info' />} />
|
||||
<Route path='basic-info' element={<BasicProfileInfoTab />} />
|
||||
<Route path='roles-skills' element={<RolesSkillsTab />} />
|
||||
<Route path='preferences' element={<PreferencesTab />
|
||||
} />
|
||||
</Routes>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { MOCK_DATA } from 'src/mocks/data';
|
||||
import CommentsSettingsCard from './CommentsSettingsCard';
|
||||
|
||||
export default {
|
||||
title: 'Profiles/Profile Page/Comments Settings Card',
|
||||
title: 'Profiles/Edit Profile Page/Comments Settings Card',
|
||||
component: CommentsSettingsCard,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
@@ -16,5 +16,6 @@ const Template: ComponentStory<typeof CommentsSettingsCard> = (args) => <Comment
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
|
||||
nostr_prv_key: "1234389753205473258327580937245",
|
||||
nostr_pub_key: "55234231277835473258327580937245",
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { MOCK_DATA } from 'src/mocks/data';
|
||||
import AccountCard from './LinkedAccountsCard';
|
||||
|
||||
export default {
|
||||
title: 'Profiles/Profile Page/Account Card',
|
||||
title: 'Profiles/Edit Profile Page/Linked Wallets Card',
|
||||
component: AccountCard,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
@@ -15,5 +16,6 @@ const Template: ComponentStory<typeof AccountCard> = (args) => <AccountCard {...
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
|
||||
value: MOCK_DATA['user'].walletsKeys,
|
||||
onChange: () => { }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from 'react'
|
||||
import Card from 'src/Components/Card/Card';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import { random } from 'src/utils/helperFunctions';
|
||||
|
||||
export default function RolesSkillsTabSkeleton() {
|
||||
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="90%" />
|
||||
</p>
|
||||
<ul className=' flex flex-wrap gap-8 mt-24'>
|
||||
{Array(10).fill(0).map((_, idx) => {
|
||||
|
||||
return <div
|
||||
key={idx}
|
||||
className={`px-12 py-8 border rounded-10 text-body5 font-medium`}
|
||||
><Skeleton width={`${Math.round(random(8, 15))}ch`} />
|
||||
</div>
|
||||
})}
|
||||
</ul>
|
||||
<div className="py-80"></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%" />
|
||||
</p>
|
||||
<ul className=' flex flex-wrap gap-x-8 gap-y-20 mt-16'>
|
||||
{Array(8).fill(0).map((_, idx) => <li key={idx} className="px-16 py-8 bg-gray-100 rounded-48 text-body5 font-medium">
|
||||
<Skeleton width={`${Math.round(random(3, 12))}ch`} />
|
||||
</li>)}
|
||||
</ul>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
|
||||
import NotFoundPage from "src/features/Shared/pages/NotFoundPage/NotFoundPage";
|
||||
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 { gql, NetworkStatus, useApolloClient } from '@apollo/client';
|
||||
import { usePrompt } from 'src/utils/hooks';
|
||||
import { UpdateUserRolesSkillsMutationVariables, useMyProfileRolesSkillsQuery, useUpdateUserRolesSkillsMutation, UserRolesSkillsFragmentDoc } from 'src/graphql'
|
||||
import UpdateRolesCard from "./UpdateRolesCard/UpdateRolesCard";
|
||||
import UpdateSkillsCard from "./UpdateSkillsCard/UpdateSkillsCard";
|
||||
import RolesSkillsTabSkeleton from "./RolesSkillsTab.Skeleton";
|
||||
|
||||
|
||||
interface Props {
|
||||
}
|
||||
|
||||
|
||||
|
||||
export type IRolesSkillsForm = NonNullable<UpdateUserRolesSkillsMutationVariables['data']>;
|
||||
|
||||
const schema: yup.SchemaOf<IRolesSkillsForm> = yup.object({
|
||||
roles: yup.array().of(
|
||||
yup.object().shape({
|
||||
id: yup.number().required(),
|
||||
level: yup.string().required(),
|
||||
}).required()
|
||||
).required(),
|
||||
skills: yup.array().of(
|
||||
yup.object().shape({
|
||||
id: yup.number().required(),
|
||||
}).required()
|
||||
).required(),
|
||||
}).required();
|
||||
|
||||
export default function PreferencesTab() {
|
||||
|
||||
const { formState: { isDirty, }, handleSubmit, reset, control } = useForm<IRolesSkillsForm>({
|
||||
defaultValues: {
|
||||
roles: [],
|
||||
skills: [],
|
||||
},
|
||||
resolver: yupResolver(schema),
|
||||
});
|
||||
|
||||
const query = useMyProfileRolesSkillsQuery({
|
||||
onCompleted: data => {
|
||||
if (data.me) reset(data.me)
|
||||
},
|
||||
notifyOnNetworkStatusChange: true,
|
||||
});
|
||||
|
||||
const apolloClient = useApolloClient()
|
||||
const [mutate, mutationStatus] = useUpdateUserRolesSkillsMutation({
|
||||
onCompleted: ({ updateProfileRoles: data }) => {
|
||||
apolloClient.writeFragment({
|
||||
id: `User:${data?.id}`,
|
||||
data: {
|
||||
roles: data?.roles,
|
||||
skills: data?.skills
|
||||
},
|
||||
fragment: UserRolesSkillsFragmentDoc,
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
usePrompt('You may have some unsaved changes. You still want to leave?', isDirty)
|
||||
|
||||
|
||||
if (query.networkStatus === NetworkStatus.loading)
|
||||
return <RolesSkillsTabSkeleton />
|
||||
|
||||
if (!query.data || !query.data?.me)
|
||||
return <NotFoundPage />
|
||||
|
||||
if (!query.data?.getAllMakersRoles || !query.data?.getAllMakersSkills)
|
||||
return null;
|
||||
|
||||
const onSubmit: SubmitHandler<IRolesSkillsForm> = data => {
|
||||
const toastId = toast.loading("Saving changes...", NotificationsService.defaultOptions)
|
||||
mutate({
|
||||
variables: {
|
||||
data: {
|
||||
roles: data.roles.map(v => ({ id: v.id, level: v.level })),
|
||||
skills: data.skills.map(v => ({ id: v.id })),
|
||||
}
|
||||
},
|
||||
onCompleted: ({ updateProfileRoles }) => {
|
||||
if (updateProfileRoles) {
|
||||
reset(updateProfileRoles);
|
||||
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 flex flex-col gap-24">
|
||||
<Controller
|
||||
control={control}
|
||||
name="roles"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<UpdateRolesCard
|
||||
allRoles={query.data?.getAllMakersRoles!}
|
||||
value={value}
|
||||
onChange={onChange} />
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="skills"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<UpdateSkillsCard
|
||||
allSkills={query.data?.getAllMakersSkills!}
|
||||
value={value}
|
||||
onChange={onChange} />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="self-start sticky-side-element">
|
||||
<SaveChangesCard
|
||||
isLoading={mutationStatus.loading}
|
||||
isDirty={isDirty}
|
||||
onSubmit={handleSubmit(onSubmit, e => console.log(e))}
|
||||
onCancel={() => reset()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { MOCK_DATA } from 'src/mocks/data';
|
||||
import UpdateRolesCard from './UpdateRolesCard';
|
||||
|
||||
export default {
|
||||
title: 'Profiles/Edit Profile Page/Update Roles Card',
|
||||
component: UpdateRolesCard,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
|
||||
} as ComponentMeta<typeof UpdateRolesCard>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof UpdateRolesCard> = (args) => <UpdateRolesCard {...args} ></UpdateRolesCard>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
value: MOCK_DATA['user'].roles,
|
||||
onChange: () => { }
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import React from 'react'
|
||||
import { Control, useFieldArray } from 'react-hook-form'
|
||||
import Card from 'src/Components/Card/Card'
|
||||
import { GenericMakerRole, MakerRole, RoleLevelEnum } from 'src/graphql'
|
||||
import { IRolesSkillsForm } from '../RolesSkillsTab'
|
||||
|
||||
type Value = Pick<MakerRole, 'id' | 'level'>
|
||||
|
||||
interface Props {
|
||||
allRoles: Pick<GenericMakerRole, 'id' | 'title' | 'icon'>[];
|
||||
value: Value[],
|
||||
onChange: (newValue: Value[]) => void
|
||||
}
|
||||
|
||||
export default function UpdateRolesCard(props: Props) {
|
||||
|
||||
const add = (idx: number) => {
|
||||
props.onChange([...props.value.slice(-2), { ...props.allRoles[idx], level: RoleLevelEnum.Beginner }])
|
||||
}
|
||||
|
||||
const remove = (idx: number) => {
|
||||
props.onChange(props.value.filter(v => v.id !== props.allRoles[idx].id))
|
||||
}
|
||||
|
||||
const setLevel = (roleId: number, level: RoleLevelEnum) => {
|
||||
props.onChange(props.value.map(v => {
|
||||
if (v.id !== roleId) return v;
|
||||
return {
|
||||
...v,
|
||||
level
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<p className="text-body2 font-bold">🎛️ Roles</p>
|
||||
<p className="text-body4 text-gray-600 mt-8"> Select your top 3 roles, and let other makers know what your level is.</p>
|
||||
<div className=' flex flex-wrap gap-8 mt-24'>
|
||||
{props.allRoles.map((role, idx) => {
|
||||
const isActive = props.value.some(v => v.id === role.id);
|
||||
|
||||
return <button
|
||||
key={role.id}
|
||||
className={`
|
||||
px-12 py-8 border rounded-10 text-body5 font-medium
|
||||
active:scale-95 transition-transform
|
||||
${!isActive ? "bg-gray-100 hover:bg-gray-200 border-gray-200" : "bg-primary-100 text-primary-600 border-primary-200"}
|
||||
`}
|
||||
onClick={() => isActive ? remove(idx) : add(idx)}
|
||||
>{role.icon} {role.title}
|
||||
</button>
|
||||
})}
|
||||
</div>
|
||||
|
||||
{props.value.length > 0 && <div className="pt-24 mt-24 border-t border-gray-200">
|
||||
<ul className="grid grid-cols-1 2xl:grid-cols-[auto_1fr] items-center gap-16">
|
||||
{props.value.map(role => {
|
||||
const { title, icon } = props.allRoles.find(r => r.id === role.id)!;
|
||||
|
||||
return <React.Fragment key={role.id}>
|
||||
<p className="shrink-0 font-medium text-body4 whitespace-nowrap">{icon} {title}</p>
|
||||
<div className="flex flex-wrap gap-8 grow text-body5 mb-8 last-of-type:mb-0">
|
||||
{[RoleLevelEnum.Beginner, RoleLevelEnum.Hobbyist, RoleLevelEnum.Intermediate, RoleLevelEnum.Advanced, RoleLevelEnum.Pro].map(r =>
|
||||
<button
|
||||
key={r}
|
||||
className={`
|
||||
px-12 py-4 bg-gray-100 border rounded-8 flex-1
|
||||
active:scale-95 transition-transform font-medium
|
||||
${r !== role.level ? "bg-gray-100 hover:bg-gray-200 border-gray-200" : "bg-primary-100 text-primary-600 border-primary-200"}
|
||||
`}
|
||||
onClick={() => setLevel(role.id, r)}
|
||||
>{r}</button>
|
||||
)}</div>
|
||||
</React.Fragment >
|
||||
})}
|
||||
</ul>
|
||||
</div>}
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
|
||||
|
||||
import Select from 'react-select';
|
||||
import { OnChangeValue, StylesConfig, components, OptionProps } from "react-select";
|
||||
import Avatar from "src/features/Profiles/Components/Avatar/Avatar";
|
||||
import { FiSearch } from 'react-icons/fi';
|
||||
import { useState } from 'react';
|
||||
import { MyProfileRolesSkillsQuery } from 'src/graphql';
|
||||
|
||||
|
||||
|
||||
type Skill = MyProfileRolesSkillsQuery['getAllMakersSkills'][number]
|
||||
|
||||
interface Props {
|
||||
classes?: {
|
||||
container?: string
|
||||
input?: string
|
||||
}
|
||||
placeholder?: string,
|
||||
onSelect?: (selectedUser: Skill) => void
|
||||
options: Skill[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// const OptionComponent = (props: OptionProps<Skill>) => {
|
||||
// return (
|
||||
// <div>
|
||||
// <components.Option {...props} className='!flex items-center gap-16 !py-16'>
|
||||
// <Avatar src={props.data.avatar} width={48} />
|
||||
// <div>
|
||||
// <p className="font-medium self-center">
|
||||
// {props.data.name}
|
||||
// </p>
|
||||
// <p className="text-body5 text-gray-500">
|
||||
// {props.data.jobTitle}
|
||||
// </p>
|
||||
// </div>
|
||||
// </components.Option>
|
||||
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
|
||||
|
||||
const colourStyles: StylesConfig = {
|
||||
|
||||
control: (styles, state) => ({
|
||||
...styles,
|
||||
padding: '5px 16px',
|
||||
borderRadius: 12,
|
||||
// border: 'none',
|
||||
// boxShadow: 'none',
|
||||
|
||||
":hover": {
|
||||
cursor: "pointer"
|
||||
},
|
||||
":focus-within": {
|
||||
'--tw-border-opacity': '1',
|
||||
borderColor: 'rgb(179 160 255 / var(--tw-border-opacity))',
|
||||
outlineColor: '#9E88FF',
|
||||
'--tw-ring-offset-shadow': 'var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)',
|
||||
'--tw-ring-shadow': 'var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)',
|
||||
boxShadow: 'var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000)',
|
||||
'--tw-ring-color': 'rgb(179 160 255 / var(--tw-ring-opacity))',
|
||||
'--tw-ring-opacity': '0.5'
|
||||
}
|
||||
|
||||
}),
|
||||
multiValueRemove: (styles) => ({
|
||||
...styles,
|
||||
":hover": {
|
||||
background: 'none'
|
||||
}
|
||||
}),
|
||||
indicatorsContainer: () => ({ display: 'none' }),
|
||||
clearIndicator: () => ({ display: 'none' }),
|
||||
indicatorSeparator: () => ({ display: "none" }),
|
||||
input: (styles, state) => ({
|
||||
...styles,
|
||||
" input": {
|
||||
boxShadow: 'none !important'
|
||||
},
|
||||
}),
|
||||
multiValue: styles => ({
|
||||
...styles,
|
||||
padding: '4px 12px',
|
||||
borderRadius: 48,
|
||||
fontWeight: 500
|
||||
}),
|
||||
valueContainer: (styles) => ({
|
||||
...styles,
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export default function SkillsInput({
|
||||
classes,
|
||||
...props }: Props) {
|
||||
|
||||
const handleChange = (newValue: OnChangeValue<Skill, false>,) => {
|
||||
if (newValue)
|
||||
props.onSelect?.(newValue);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${classes?.container}`}>
|
||||
<Select
|
||||
value={null}
|
||||
placeholder={'Search and add skill'}
|
||||
options={props.options}
|
||||
onChange={handleChange as any}
|
||||
styles={colourStyles as any}
|
||||
getOptionLabel={o => o?.title!}
|
||||
maxMenuHeight={Math.max(200, Math.min(window.innerHeight / 5, 400))}
|
||||
theme={(theme) => ({
|
||||
...theme,
|
||||
borderRadius: 8,
|
||||
colors: {
|
||||
...theme.colors,
|
||||
primary: 'var(--primary)',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { MOCK_DATA } from 'src/mocks/data';
|
||||
import UpdateSkillsCard from './UpdateSkillsCard';
|
||||
|
||||
export default {
|
||||
title: 'Profiles/Edit Profile Page/Update Skills Card',
|
||||
component: UpdateSkillsCard,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
|
||||
} as ComponentMeta<typeof UpdateSkillsCard>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof UpdateSkillsCard> = (args) => <UpdateSkillsCard {...args} ></UpdateSkillsCard>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
value: MOCK_DATA['user'].skills,
|
||||
onChange: () => { }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { GrClose } from 'react-icons/gr'
|
||||
import Card from 'src/Components/Card/Card'
|
||||
import { MakerSkill } from 'src/graphql'
|
||||
import SkillsInput from './SkillsInput'
|
||||
|
||||
type Value = Pick<MakerSkill, 'id'>
|
||||
|
||||
interface Props {
|
||||
allSkills: Pick<MakerSkill, 'id' | 'title'>[];
|
||||
value: Value[],
|
||||
onChange: (newValue: Value[]) => void
|
||||
}
|
||||
|
||||
export default function UpdateSkillsCard(props: Props) {
|
||||
|
||||
const add = (newValue: Value) => {
|
||||
props.onChange([...props.value, newValue])
|
||||
}
|
||||
|
||||
const idToValue = useMemo(() => {
|
||||
const map = new Map<number, Props['allSkills'][number]>();
|
||||
for (let i = 0; i < props.allSkills.length; i++) {
|
||||
const element = props.allSkills[i];
|
||||
map.set(element.id, element);
|
||||
}
|
||||
return map;
|
||||
}, [props.allSkills])
|
||||
|
||||
const remove = (id: number) => {
|
||||
props.onChange(props.value.filter(v => v.id !== id))
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<p className="text-body2 font-bold">🌈 Skills</p>
|
||||
<p className="text-body4 text-gray-600 mt-8">Add some of your skills and let other makers know what you’re good at.</p>
|
||||
<div className="mt-16">
|
||||
<SkillsInput options={props.allSkills.filter(skill => !props.value.some(v => v.id === skill.id))} onSelect={add} />
|
||||
</div>
|
||||
{props.value.length > 0 && <ul className=' flex flex-wrap gap-x-8 gap-y-20 mt-16'>
|
||||
{props.value.map((skill) => <li key={skill.id} className="px-16 py-8 bg-gray-100 rounded-48 text-body5 font-medium">
|
||||
{idToValue.get(skill.id)?.title} <button className='ml-8' onClick={() => remove(skill.id)}><GrClose /></button>
|
||||
</li>)}
|
||||
</ul>}
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
fragment UserRolesSkills on BaseUser {
|
||||
skills {
|
||||
id
|
||||
title
|
||||
}
|
||||
roles {
|
||||
id
|
||||
title
|
||||
icon
|
||||
level
|
||||
}
|
||||
}
|
||||
|
||||
query MyProfileRolesSkills {
|
||||
me {
|
||||
id
|
||||
...UserRolesSkills
|
||||
}
|
||||
getAllMakersRoles {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
getAllMakersSkills {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
|
||||
mutation UpdateUserRolesSkills($data: ProfileRolesInput) {
|
||||
updateProfileRoles(data: $data) {
|
||||
id
|
||||
skills {
|
||||
id
|
||||
title
|
||||
}
|
||||
roles {
|
||||
id
|
||||
title
|
||||
icon
|
||||
level
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -29,24 +29,28 @@ export default function AboutCard({ user, isOwner }: Props) {
|
||||
hasValue: user.website,
|
||||
text: user.website?.replace(/(^\w+:|^)\/\//, '').replace(/\/$/, ""),
|
||||
icon: FiGlobe,
|
||||
colors: "bg-gray-100 text-gray-900",
|
||||
url: user.website && withHttp(user.website)
|
||||
},
|
||||
{
|
||||
hasValue: user.twitter,
|
||||
text: user.twitter,
|
||||
icon: FiTwitter,
|
||||
colors: "bg-blue-100 text-blue-500",
|
||||
url: `https://twitter.com/@${user.twitter}`
|
||||
},
|
||||
{
|
||||
hasValue: user.github,
|
||||
text: user.github,
|
||||
icon: FiGithub,
|
||||
colors: "bg-pink-100 text-pink-600",
|
||||
url: `https://github.com/${user.github}`
|
||||
},
|
||||
{
|
||||
hasValue: user.linkedin,
|
||||
text: "LinkedIn",
|
||||
icon: FiLinkedin,
|
||||
colors: "bg-sky-100 text-cyan-600",
|
||||
url: user.linkedin && withHttp(user.linkedin),
|
||||
}
|
||||
];
|
||||
@@ -65,37 +69,41 @@ export default function AboutCard({ user, isOwner }: Props) {
|
||||
</div>
|
||||
<div className="p-24 pt-0">
|
||||
<div className="flex flex-col gap-16">
|
||||
<h1 className="text-h2 font-bolder break-words">
|
||||
{user.name}
|
||||
</h1>
|
||||
<div>
|
||||
<h1 className="text-h2 font-bolder break-words">
|
||||
{user.name}
|
||||
</h1>
|
||||
|
||||
{links.some(link => link.hasValue) && <div className="flex flex-wrap gap-16">
|
||||
{<p className="text-body3 font-medium text-gray-600">
|
||||
{user.jobTitle ? user.jobTitle : "No job title added"}
|
||||
</p>}
|
||||
</div>
|
||||
{<div className="flex flex-wrap gap-16">
|
||||
{links.filter(link => link.hasValue || isOwner).map((link, idx) => link.hasValue ?
|
||||
<a
|
||||
key={idx}
|
||||
href={link.url!}
|
||||
className="text-body4 text-primary-700 font-medium"
|
||||
className={`w-40 aspect-square rounded-full flex justify-center items-center ${link.colors}`}
|
||||
target='_blank'
|
||||
rel="noreferrer">
|
||||
<link.icon className="scale-125 mr-8" /> <span className="align-middle">{link.text}</span>
|
||||
</a> :
|
||||
<p
|
||||
key={idx}
|
||||
className="text-body4 text-primary-700 font-medium"
|
||||
>
|
||||
<link.icon className="scale-125 mr-8" /> <span className="align-middle">---</span>
|
||||
</p>)}
|
||||
<link.icon className="scale-125" />
|
||||
</a>
|
||||
:
|
||||
(isOwner &&
|
||||
<p
|
||||
key={idx}
|
||||
className={`text-body4 py-8 px-16 rounded-24 font-medium ${link.colors}`}
|
||||
>
|
||||
<link.icon className="scale-125 mr-8" /> <span className="align-middle">---</span>
|
||||
</p>))}
|
||||
</div>}
|
||||
|
||||
{(user.jobTitle || isOwner) && <p className="text-body4 font-medium">
|
||||
{user.jobTitle ? user.jobTitle : "No job title added"}
|
||||
</p>}
|
||||
|
||||
{(user.lightning_address || isOwner) && <p className="text-body5 font-medium">
|
||||
{<p className="text-body5 font-medium">
|
||||
{user.lightning_address ? `⚡${user.lightning_address}` : "⚡ No lightning address"}
|
||||
</p>}
|
||||
|
||||
{(user.bio || isOwner) && <p className="text-body5 font-medium">
|
||||
{<p className="text-body5 font-medium">
|
||||
{user.bio ? user.bio : "No bio added"}
|
||||
</p>}
|
||||
</div>
|
||||
|
||||
@@ -4,9 +4,16 @@ import NotFoundPage from "src/features/Shared/pages/NotFoundPage/NotFoundPage"
|
||||
import { useProfileQuery } from "src/graphql"
|
||||
import AboutCard from "./AboutCard/AboutCard"
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { useAppSelector } from 'src/utils/hooks';
|
||||
import { useAppSelector, useMediaQuery } from 'src/utils/hooks';
|
||||
import styles from './styles.module.scss'
|
||||
import StoriesCard from "./StoriesCard/StoriesCard"
|
||||
import RolesCard from "./RolesCard/RolesCard"
|
||||
import SkillsCard from "./SkillsCard/SkillsCard"
|
||||
import TournamentsCard from "./TournamentsCard/TournamentsCard"
|
||||
import { MEDIA_QUERIES } from "src/utils/theme"
|
||||
import SimilarMakersCard from "./SimilarMakersCard/SimilarMakersCard"
|
||||
import { useEffect } from "react"
|
||||
import { gql, useApolloClient } from "@apollo/client"
|
||||
|
||||
export default function ProfilePage() {
|
||||
|
||||
@@ -17,7 +24,12 @@ export default function ProfilePage() {
|
||||
},
|
||||
skip: isNaN(Number(id)),
|
||||
})
|
||||
const isOwner = useAppSelector(state => Boolean(state.user.me?.id && state.user.me?.id === profileQuery.data?.profile?.id))
|
||||
const { isOwner } = useAppSelector(state => ({
|
||||
isOwner: Boolean(state.user.me?.id && state.user.me?.id === profileQuery.data?.profile?.id),
|
||||
}))
|
||||
|
||||
const isMediumScreen = useMediaQuery(MEDIA_QUERIES.isMedium)
|
||||
|
||||
|
||||
|
||||
if (profileQuery.loading)
|
||||
@@ -26,6 +38,7 @@ export default function ProfilePage() {
|
||||
if (!profileQuery.data?.profile)
|
||||
return <NotFoundPage />
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
@@ -39,12 +52,33 @@ export default function ProfilePage() {
|
||||
</Helmet>
|
||||
<div className={`page-container ${styles.grid}`}
|
||||
>
|
||||
<aside></aside>
|
||||
<main className="flex flex-col gap-24">
|
||||
<AboutCard user={profileQuery.data.profile} isOwner={isOwner} />
|
||||
<StoriesCard stories={profileQuery.data.profile.stories} isOwner={isOwner} />
|
||||
</main>
|
||||
<aside></aside>
|
||||
{isMediumScreen ?
|
||||
<>
|
||||
<aside>
|
||||
|
||||
<RolesCard roles={profileQuery.data.profile.roles} isOwner={isOwner} />
|
||||
<SkillsCard skills={profileQuery.data.profile.skills} isOwner={isOwner} />
|
||||
<TournamentsCard tournaments={profileQuery.data.profile.tournaments} isOwner={isOwner} />
|
||||
</aside>
|
||||
<main>
|
||||
|
||||
<AboutCard user={profileQuery.data.profile} isOwner={isOwner} />
|
||||
<StoriesCard stories={profileQuery.data.profile.stories} isOwner={isOwner} />
|
||||
</main>
|
||||
<aside>
|
||||
<SimilarMakersCard makers={profileQuery.data.profile.similar_makers} />
|
||||
</aside>
|
||||
</>
|
||||
:
|
||||
<>
|
||||
<main>
|
||||
<AboutCard user={profileQuery.data.profile} isOwner={isOwner} />
|
||||
<RolesCard roles={profileQuery.data.profile.roles} isOwner={isOwner} />
|
||||
<SkillsCard skills={profileQuery.data.profile.skills} isOwner={isOwner} />
|
||||
<StoriesCard stories={profileQuery.data.profile.stories} isOwner={isOwner} />
|
||||
</main>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { MOCK_DATA } from 'src/mocks/data';
|
||||
import RolesCard from './RolesCard';
|
||||
|
||||
export default {
|
||||
title: 'Profiles/Profile Page/Roles Card',
|
||||
component: RolesCard,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
|
||||
} as ComponentMeta<typeof RolesCard>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof RolesCard> = (args) => <div className="max-w-[326px]"><RolesCard {...args} ></RolesCard></div>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
roles: MOCK_DATA['user'].roles
|
||||
}
|
||||
|
||||
export const Empty = Template.bind({});
|
||||
Empty.args = {
|
||||
roles: [],
|
||||
}
|
||||
|
||||
export const EmptyOwner = Template.bind({});
|
||||
EmptyOwner.args = {
|
||||
roles: [],
|
||||
isOwner: true
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import Card from 'src/Components/Card/Card'
|
||||
import Button from 'src/Components/Button/Button'
|
||||
import { RoleLevelEnum, User } from 'src/graphql';
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
roles: User['roles'][number][]
|
||||
isOwner?: boolean;
|
||||
}
|
||||
|
||||
export default function RolesCard({ roles, isOwner }: Props) {
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<p className="text-body2 font-bold">🎛️ Roles</p>
|
||||
<div className="mt-16">
|
||||
{roles.length === 0 && <>
|
||||
<p className="text-gray-700 text-body4">No roles added</p>
|
||||
{isOwner && <Button color='primary' className='mt-16' size='sm' href='/edit-profile/roles-skills'>Add roles</Button>}
|
||||
</>}
|
||||
<ul className=' flex flex-col gap-16'>
|
||||
{
|
||||
roles
|
||||
.map(role => {
|
||||
|
||||
let levelInt = 0;
|
||||
if (role.level === RoleLevelEnum.Hobbyist) levelInt = 1;
|
||||
if (role.level === RoleLevelEnum.Intermediate) levelInt = 2;
|
||||
if (role.level === RoleLevelEnum.Advanced) levelInt = 3;
|
||||
if (role.level === RoleLevelEnum.Pro) levelInt = 4;
|
||||
return {
|
||||
...role,
|
||||
level: levelInt
|
||||
}
|
||||
})
|
||||
.sort((a, b) => b.level - a.level)
|
||||
.map((role) => <li
|
||||
key={role.id}
|
||||
className={`flex gap-16 items-center rounded-8 cursor-pointer font-bold p-4active:scale-95 transition-transform`}
|
||||
>
|
||||
<span className={`bg-gray-50 rounded-8 w-40 h-40 text-center py-8`}>{role.icon}</span>
|
||||
<div className='grow'>
|
||||
<p className="font-medium text-body5 text-gray-800">
|
||||
{role.title}
|
||||
</p>
|
||||
<div className="flex gap-4 mt-16">
|
||||
{Array(5).fill(0).map((_, idx) => {
|
||||
return <div key={idx} className={`flex-1 h-[2px] rounded-4 ${(idx) <= role.level ? "bg-primary-500" : "bg-gray-100"}`} />
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { MOCK_DATA } from 'src/mocks/data';
|
||||
|
||||
import SimilarMakersCard from './SimilarMakersCard';
|
||||
|
||||
export default {
|
||||
title: 'Profiles/Profile Page/Similar Makers Card',
|
||||
component: SimilarMakersCard,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
} as ComponentMeta<typeof SimilarMakersCard>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof SimilarMakersCard> = (args) => <div className="max-w-[326px]"><SimilarMakersCard {...args as any} ></SimilarMakersCard></div>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
makers: MOCK_DATA['user'].similar_makers
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
import { Link } from 'react-router-dom'
|
||||
import Card from 'src/Components/Card/Card'
|
||||
import Avatar from 'src/features/Profiles/Components/Avatar/Avatar'
|
||||
import { User } from 'src/graphql'
|
||||
import { createRoute } from 'src/utils/routing'
|
||||
|
||||
interface Props {
|
||||
makers: Pick<User,
|
||||
| "id"
|
||||
| "name"
|
||||
| "jobTitle"
|
||||
| 'avatar'
|
||||
>[]
|
||||
}
|
||||
|
||||
export default function SimilarMakersCard({ makers }: Props) {
|
||||
|
||||
|
||||
return (
|
||||
<Card onlyMd>
|
||||
<h3 className="text-body2 font-bolder">Similar makers</h3>
|
||||
<ul className='flex flex-col'>
|
||||
{makers.map(maker => {
|
||||
return <Link key={maker.id} to={createRoute({ type: "profile", id: maker.id, username: maker.name })} className="border-b py-16 last-of-type:border-b-0 last-of-type:pb-0">
|
||||
<li className="flex items-start gap-8">
|
||||
<Avatar width={40} src={maker.avatar} />
|
||||
<div>
|
||||
<p className="text-body4 text-gray-800 font-medium">{maker.name}</p>
|
||||
<p className="text-body5 text-gray-500 font-medium">{maker.jobTitle}</p>
|
||||
</div>
|
||||
</li>
|
||||
</Link>
|
||||
})}
|
||||
</ul>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { MOCK_DATA } from 'src/mocks/data';
|
||||
import SkillsCard from './SkillsCard';
|
||||
|
||||
export default {
|
||||
title: 'Profiles/Profile Page/Skills Card',
|
||||
component: SkillsCard,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
|
||||
} as ComponentMeta<typeof SkillsCard>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof SkillsCard> = (args) => <div className="max-w-[326px]"><SkillsCard {...args} ></SkillsCard></div>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
skills: MOCK_DATA['user'].skills
|
||||
}
|
||||
|
||||
export const Empty = Template.bind({});
|
||||
Empty.args = {
|
||||
skills: [],
|
||||
}
|
||||
|
||||
export const EmptyOwner = Template.bind({});
|
||||
EmptyOwner.args = {
|
||||
skills: [],
|
||||
isOwner: true
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import Card from 'src/Components/Card/Card'
|
||||
import Button from 'src/Components/Button/Button'
|
||||
import { User } from 'src/graphql';
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
skills: User['skills'][number][]
|
||||
isOwner: boolean;
|
||||
}
|
||||
|
||||
export default function SkillsCard({ skills, isOwner }: Props) {
|
||||
return (
|
||||
<Card>
|
||||
<p className="text-body2 font-bold">🌈 Skills</p>
|
||||
<div className="mt-16">
|
||||
{skills.length === 0 && <>
|
||||
<p className="text-gray-700 text-body4">No skills added</p>
|
||||
{isOwner && <Button color='primary' className='mt-16' size='sm' href='/edit-profile/roles-skills'>Add skills</Button>}
|
||||
</>}
|
||||
<ul className=' flex flex-wrap gap-x-8 gap-y-20'>
|
||||
{skills.map((skill) => <li key={skill.id} className="text-body5 border border-gray-200 px-12 py-4 bg-gray-100 rounded-48 font-medium">{skill.title}</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { MOCK_DATA } from 'src/mocks/data';
|
||||
import TournamentsCard from './TournamentsCard';
|
||||
|
||||
export default {
|
||||
title: 'Profiles/Profile Page/Tournaments Card',
|
||||
component: TournamentsCard,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
|
||||
} as ComponentMeta<typeof TournamentsCard>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof TournamentsCard> = (args) => <div className="max-w-[326px]"><TournamentsCard {...args} ></TournamentsCard></div>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
tournaments: MOCK_DATA['user'].tournaments
|
||||
}
|
||||
|
||||
export const Empty = Template.bind({});
|
||||
Empty.args = {
|
||||
tournaments: [],
|
||||
}
|
||||
|
||||
export const EmptyOwner = Template.bind({});
|
||||
EmptyOwner.args = {
|
||||
tournaments: [],
|
||||
isOwner: true
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import Card from 'src/Components/Card/Card'
|
||||
import Button from 'src/Components/Button/Button'
|
||||
import { RoleLevelEnum, User } from 'src/graphql';
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
tournaments: Pick<User['tournaments'][number],
|
||||
| 'id'
|
||||
| 'title'
|
||||
| 'thumbnail_image'
|
||||
| 'start_date'
|
||||
| 'end_date'
|
||||
>[]
|
||||
isOwner?: boolean;
|
||||
}
|
||||
|
||||
export default function TournamentsCard({ tournaments, isOwner }: Props) {
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<p className="text-body2 font-bold">🏆 Tournaments </p>
|
||||
<div className="mt-16">
|
||||
{tournaments.length === 0 && <>
|
||||
<p className="text-gray-700 text-body4">No tournaments entered.</p>
|
||||
</>}
|
||||
<ul className=' flex flex-wrap gap-x-8 gap-y-20'>
|
||||
{
|
||||
tournaments.map((tournament) => {
|
||||
|
||||
const isLive = ((new Date() < new Date(tournament.end_date)) && (new Date() > new Date(tournament.start_date)));
|
||||
|
||||
return <li key={tournament.id} className="flex gap-16 items-center">
|
||||
<img src={tournament.thumbnail_image} className='w-48 border-2 border-gray-100 aspect-square rounded-16 object-cover' alt="" />
|
||||
<div>
|
||||
<p className="text-gray-900 font-medium">{tournament.title}</p>
|
||||
<p className={`${isLive ? "text-green-500" : "text-warning-500"} text-body5 font-medium`}>• {isLive ? "Live" : "Completed"}</p>
|
||||
</div>
|
||||
</li>
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +1,5 @@
|
||||
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
|
||||
@@ -24,5 +10,20 @@ query profile($profileId: Int!) {
|
||||
icon
|
||||
}
|
||||
}
|
||||
tournaments {
|
||||
id
|
||||
title
|
||||
thumbnail_image
|
||||
start_date
|
||||
end_date
|
||||
}
|
||||
similar_makers {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
jobTitle
|
||||
}
|
||||
...UserBasicInfo
|
||||
...UserRolesSkills
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,21 @@
|
||||
grid-template-areas: "main";
|
||||
|
||||
> aside:first-of-type {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
grid-area: aside1;
|
||||
}
|
||||
> main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
grid-area: main;
|
||||
}
|
||||
> aside:last-of-type {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
grid-area: aside2;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,11 @@ export type BaseUser = {
|
||||
location: Maybe<Scalars['String']>;
|
||||
name: Scalars['String'];
|
||||
role: Maybe<Scalars['String']>;
|
||||
roles: Array<MakerRole>;
|
||||
similar_makers: Array<User>;
|
||||
skills: Array<MakerSkill>;
|
||||
stories: Array<Story>;
|
||||
tournaments: Array<Tournament>;
|
||||
twitter: Maybe<Scalars['String']>;
|
||||
website: Maybe<Scalars['String']>;
|
||||
};
|
||||
@@ -111,6 +115,13 @@ export type DonationsStats = {
|
||||
touranments: Scalars['String'];
|
||||
};
|
||||
|
||||
export type GenericMakerRole = {
|
||||
__typename?: 'GenericMakerRole';
|
||||
icon: Scalars['String'];
|
||||
id: Scalars['Int'];
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
export type Hackathon = {
|
||||
__typename?: 'Hackathon';
|
||||
cover_image: Scalars['String'];
|
||||
@@ -132,6 +143,29 @@ export type LnurlDetails = {
|
||||
minSendable: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type MakerRole = {
|
||||
__typename?: 'MakerRole';
|
||||
icon: Scalars['String'];
|
||||
id: Scalars['Int'];
|
||||
level: RoleLevelEnum;
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
export type MakerRoleInput = {
|
||||
id: Scalars['Int'];
|
||||
level: RoleLevelEnum;
|
||||
};
|
||||
|
||||
export type MakerSkill = {
|
||||
__typename?: 'MakerSkill';
|
||||
id: Scalars['Int'];
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
export type MakerSkillInput = {
|
||||
id: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type Mutation = {
|
||||
__typename?: 'Mutation';
|
||||
confirmDonation: Donation;
|
||||
@@ -140,6 +174,7 @@ export type Mutation = {
|
||||
deleteStory: Maybe<Story>;
|
||||
donate: Donation;
|
||||
updateProfileDetails: Maybe<MyProfile>;
|
||||
updateProfileRoles: Maybe<MyProfile>;
|
||||
updateUserPreferences: MyProfile;
|
||||
vote: Vote;
|
||||
};
|
||||
@@ -177,6 +212,11 @@ export type MutationUpdateProfileDetailsArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateProfileRolesArgs = {
|
||||
data: InputMaybe<ProfileRolesInput>;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateUserPreferencesArgs = {
|
||||
userKeys: InputMaybe<Array<UserKeyInputType>>;
|
||||
};
|
||||
@@ -204,7 +244,11 @@ export type MyProfile = BaseUser & {
|
||||
nostr_prv_key: Maybe<Scalars['String']>;
|
||||
nostr_pub_key: Maybe<Scalars['String']>;
|
||||
role: Maybe<Scalars['String']>;
|
||||
roles: Array<MakerRole>;
|
||||
similar_makers: Array<User>;
|
||||
skills: Array<MakerSkill>;
|
||||
stories: Array<Story>;
|
||||
tournaments: Array<Tournament>;
|
||||
twitter: Maybe<Scalars['String']>;
|
||||
walletsKeys: Array<WalletKey>;
|
||||
website: Maybe<Scalars['String']>;
|
||||
@@ -253,6 +297,11 @@ export type ProfileDetailsInput = {
|
||||
website: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ProfileRolesInput = {
|
||||
roles: Array<MakerRoleInput>;
|
||||
skills: Array<MakerSkillInput>;
|
||||
};
|
||||
|
||||
export type Project = {
|
||||
__typename?: 'Project';
|
||||
awards: Array<Award>;
|
||||
@@ -275,6 +324,8 @@ export type Query = {
|
||||
allCategories: Array<Category>;
|
||||
allProjects: Array<Project>;
|
||||
getAllHackathons: Array<Hackathon>;
|
||||
getAllMakersRoles: Array<GenericMakerRole>;
|
||||
getAllMakersSkills: Array<MakerSkill>;
|
||||
getCategory: Category;
|
||||
getDonationsStats: DonationsStats;
|
||||
getFeed: Array<Post>;
|
||||
@@ -291,6 +342,7 @@ export type Query = {
|
||||
profile: Maybe<User>;
|
||||
projectsByCategory: Array<Project>;
|
||||
searchProjects: Array<Project>;
|
||||
similarMakers: Array<User>;
|
||||
};
|
||||
|
||||
|
||||
@@ -370,6 +422,11 @@ export type QuerySearchProjectsArgs = {
|
||||
take?: InputMaybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
|
||||
export type QuerySimilarMakersArgs = {
|
||||
id: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type Question = PostBase & {
|
||||
__typename?: 'Question';
|
||||
author: Author;
|
||||
@@ -385,6 +442,14 @@ export type Question = PostBase & {
|
||||
votes_count: Scalars['Int'];
|
||||
};
|
||||
|
||||
export enum RoleLevelEnum {
|
||||
Advanced = 'Advanced',
|
||||
Beginner = 'Beginner',
|
||||
Hobbyist = 'Hobbyist',
|
||||
Intermediate = 'Intermediate',
|
||||
Pro = 'Pro'
|
||||
}
|
||||
|
||||
export type Story = PostBase & {
|
||||
__typename?: 'Story';
|
||||
author: Author;
|
||||
@@ -421,6 +486,19 @@ export type Tag = {
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
export type Tournament = {
|
||||
__typename?: 'Tournament';
|
||||
cover_image: Scalars['String'];
|
||||
description: Scalars['String'];
|
||||
end_date: Scalars['Date'];
|
||||
id: Scalars['Int'];
|
||||
start_date: Scalars['Date'];
|
||||
tags: Array<Tag>;
|
||||
thumbnail_image: Scalars['String'];
|
||||
title: Scalars['String'];
|
||||
website: Scalars['String'];
|
||||
};
|
||||
|
||||
export type User = BaseUser & {
|
||||
__typename?: 'User';
|
||||
avatar: Scalars['String'];
|
||||
@@ -435,7 +513,11 @@ export type User = BaseUser & {
|
||||
location: Maybe<Scalars['String']>;
|
||||
name: Scalars['String'];
|
||||
role: Maybe<Scalars['String']>;
|
||||
roles: Array<MakerRole>;
|
||||
similar_makers: Array<User>;
|
||||
skills: Array<MakerSkill>;
|
||||
stories: Array<Story>;
|
||||
tournaments: Array<Tournament>;
|
||||
twitter: Maybe<Scalars['String']>;
|
||||
website: Maybe<Scalars['String']>;
|
||||
};
|
||||
@@ -570,17 +652,11 @@ 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; }>;
|
||||
type UserBasicInfo_MyProfile_Fragment = { __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 };
|
||||
|
||||
type UserBasicInfo_User_Fragment = { __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 };
|
||||
|
||||
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 UserBasicInfoFragment = UserBasicInfo_MyProfile_Fragment | UserBasicInfo_User_Fragment;
|
||||
|
||||
export type MyProfileAboutQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -594,12 +670,42 @@ export type UpdateProfileAboutMutationVariables = Exact<{
|
||||
|
||||
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 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 }> } };
|
||||
|
||||
type UserRolesSkills_MyProfile_Fragment = { __typename?: 'MyProfile', skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }>, roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }> };
|
||||
|
||||
type UserRolesSkills_User_Fragment = { __typename?: 'User', skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }>, roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }> };
|
||||
|
||||
export type UserRolesSkillsFragment = UserRolesSkills_MyProfile_Fragment | UserRolesSkills_User_Fragment;
|
||||
|
||||
export type MyProfileRolesSkillsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type MyProfileRolesSkillsQuery = { __typename?: 'Query', me: { __typename?: 'MyProfile', id: number, skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }>, roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }> } | null, getAllMakersRoles: Array<{ __typename?: 'GenericMakerRole', id: number, title: string, icon: string }>, getAllMakersSkills: Array<{ __typename?: 'MakerSkill', id: number, title: string }> };
|
||||
|
||||
export type UpdateUserRolesSkillsMutationVariables = Exact<{
|
||||
data: InputMaybe<ProfileRolesInput>;
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateUserRolesSkillsMutation = { __typename?: 'Mutation', updateProfileRoles: { __typename?: 'MyProfile', id: number, skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }>, roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }> } | 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, 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 }> }>, tournaments: Array<{ __typename?: 'Tournament', id: number, title: string, thumbnail_image: string, start_date: any, end_date: any }>, similar_makers: Array<{ __typename?: 'User', id: number, name: string, avatar: string, jobTitle: string | null }>, skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }>, roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }> } | null };
|
||||
|
||||
export type CategoryPageQueryVariables = Exact<{
|
||||
categoryId: Scalars['Int'];
|
||||
@@ -647,7 +753,38 @@ export type ConfirmVoteMutationVariables = Exact<{
|
||||
|
||||
export type ConfirmVoteMutation = { __typename?: 'Mutation', confirmVote: { __typename?: 'Vote', id: number, amount_in_sat: number, payment_request: string, payment_hash: string, paid: boolean, item_type: Vote_Item_Type, item_id: number } };
|
||||
|
||||
|
||||
export const UserBasicInfoFragmentDoc = gql`
|
||||
fragment UserBasicInfo on BaseUser {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
join_date
|
||||
role
|
||||
email
|
||||
jobTitle
|
||||
lightning_address
|
||||
website
|
||||
twitter
|
||||
github
|
||||
linkedin
|
||||
bio
|
||||
location
|
||||
}
|
||||
`;
|
||||
export const UserRolesSkillsFragmentDoc = gql`
|
||||
fragment UserRolesSkills on BaseUser {
|
||||
skills {
|
||||
id
|
||||
title
|
||||
}
|
||||
roles {
|
||||
id
|
||||
title
|
||||
icon
|
||||
level
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const OfficialTagsDocument = gql`
|
||||
query OfficialTags {
|
||||
officialTags {
|
||||
@@ -1380,6 +1517,73 @@ 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 MyProfileAboutDocument = gql`
|
||||
query MyProfileAbout {
|
||||
me {
|
||||
...UserBasicInfo
|
||||
}
|
||||
}
|
||||
${UserBasicInfoFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __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) {
|
||||
...UserBasicInfo
|
||||
}
|
||||
}
|
||||
${UserBasicInfoFragmentDoc}`;
|
||||
export type UpdateProfileAboutMutationFn = Apollo.MutationFunction<UpdateProfileAboutMutation, UpdateProfileAboutMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useUpdateProfileAboutMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useUpdateProfileAboutMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useUpdateProfileAboutMutation` 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 [updateProfileAboutMutation, { data, loading, error }] = useUpdateProfileAboutMutation({
|
||||
* variables: {
|
||||
* data: // value for 'data'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useUpdateProfileAboutMutation(baseOptions?: Apollo.MutationHookOptions<UpdateProfileAboutMutation, UpdateProfileAboutMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<UpdateProfileAboutMutation, UpdateProfileAboutMutationVariables>(UpdateProfileAboutDocument, options);
|
||||
}
|
||||
export type UpdateProfileAboutMutationHookResult = ReturnType<typeof useUpdateProfileAboutMutation>;
|
||||
export type UpdateProfileAboutMutationResult = Apollo.MutationResult<UpdateProfileAboutMutation>;
|
||||
export type UpdateProfileAboutMutationOptions = Apollo.BaseMutationOptions<UpdateProfileAboutMutation, UpdateProfileAboutMutationVariables>;
|
||||
export const MyProfilePreferencesDocument = gql`
|
||||
query MyProfilePreferences {
|
||||
me {
|
||||
@@ -1459,116 +1663,96 @@ export function useUpdateUserPreferencesMutation(baseOptions?: Apollo.MutationHo
|
||||
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 {
|
||||
export const MyProfileRolesSkillsDocument = gql`
|
||||
query MyProfileRolesSkills {
|
||||
me {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
join_date
|
||||
role
|
||||
email
|
||||
jobTitle
|
||||
lightning_address
|
||||
website
|
||||
twitter
|
||||
github
|
||||
linkedin
|
||||
bio
|
||||
location
|
||||
...UserRolesSkills
|
||||
}
|
||||
getAllMakersRoles {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
getAllMakersSkills {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`;
|
||||
${UserRolesSkillsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useMyProfileAboutQuery__
|
||||
* __useMyProfileRolesSkillsQuery__
|
||||
*
|
||||
* 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
|
||||
* To run a query within a React component, call `useMyProfileRolesSkillsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useMyProfileRolesSkillsQuery` 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({
|
||||
* const { data, loading, error } = useMyProfileRolesSkillsQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useMyProfileAboutQuery(baseOptions?: Apollo.QueryHookOptions<MyProfileAboutQuery, MyProfileAboutQueryVariables>) {
|
||||
export function useMyProfileRolesSkillsQuery(baseOptions?: Apollo.QueryHookOptions<MyProfileRolesSkillsQuery, MyProfileRolesSkillsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<MyProfileAboutQuery, MyProfileAboutQueryVariables>(MyProfileAboutDocument, options);
|
||||
return Apollo.useQuery<MyProfileRolesSkillsQuery, MyProfileRolesSkillsQueryVariables>(MyProfileRolesSkillsDocument, options);
|
||||
}
|
||||
export function useMyProfileAboutLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MyProfileAboutQuery, MyProfileAboutQueryVariables>) {
|
||||
export function useMyProfileRolesSkillsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MyProfileRolesSkillsQuery, MyProfileRolesSkillsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<MyProfileAboutQuery, MyProfileAboutQueryVariables>(MyProfileAboutDocument, options);
|
||||
return Apollo.useLazyQuery<MyProfileRolesSkillsQuery, MyProfileRolesSkillsQueryVariables>(MyProfileRolesSkillsDocument, 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) {
|
||||
export type MyProfileRolesSkillsQueryHookResult = ReturnType<typeof useMyProfileRolesSkillsQuery>;
|
||||
export type MyProfileRolesSkillsLazyQueryHookResult = ReturnType<typeof useMyProfileRolesSkillsLazyQuery>;
|
||||
export type MyProfileRolesSkillsQueryResult = Apollo.QueryResult<MyProfileRolesSkillsQuery, MyProfileRolesSkillsQueryVariables>;
|
||||
export const UpdateUserRolesSkillsDocument = gql`
|
||||
mutation UpdateUserRolesSkills($data: ProfileRolesInput) {
|
||||
updateProfileRoles(data: $data) {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
join_date
|
||||
role
|
||||
email
|
||||
jobTitle
|
||||
lightning_address
|
||||
website
|
||||
twitter
|
||||
github
|
||||
linkedin
|
||||
bio
|
||||
location
|
||||
skills {
|
||||
id
|
||||
title
|
||||
}
|
||||
roles {
|
||||
id
|
||||
title
|
||||
icon
|
||||
level
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type UpdateProfileAboutMutationFn = Apollo.MutationFunction<UpdateProfileAboutMutation, UpdateProfileAboutMutationVariables>;
|
||||
export type UpdateUserRolesSkillsMutationFn = Apollo.MutationFunction<UpdateUserRolesSkillsMutation, UpdateUserRolesSkillsMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useUpdateProfileAboutMutation__
|
||||
* __useUpdateUserRolesSkillsMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useUpdateProfileAboutMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useUpdateProfileAboutMutation` returns a tuple that includes:
|
||||
* To run a mutation, you first call `useUpdateUserRolesSkillsMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useUpdateUserRolesSkillsMutation` 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 [updateProfileAboutMutation, { data, loading, error }] = useUpdateProfileAboutMutation({
|
||||
* const [updateUserRolesSkillsMutation, { data, loading, error }] = useUpdateUserRolesSkillsMutation({
|
||||
* variables: {
|
||||
* data: // value for 'data'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useUpdateProfileAboutMutation(baseOptions?: Apollo.MutationHookOptions<UpdateProfileAboutMutation, UpdateProfileAboutMutationVariables>) {
|
||||
export function useUpdateUserRolesSkillsMutation(baseOptions?: Apollo.MutationHookOptions<UpdateUserRolesSkillsMutation, UpdateUserRolesSkillsMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<UpdateProfileAboutMutation, UpdateProfileAboutMutationVariables>(UpdateProfileAboutDocument, options);
|
||||
return Apollo.useMutation<UpdateUserRolesSkillsMutation, UpdateUserRolesSkillsMutationVariables>(UpdateUserRolesSkillsDocument, options);
|
||||
}
|
||||
export type UpdateProfileAboutMutationHookResult = ReturnType<typeof useUpdateProfileAboutMutation>;
|
||||
export type UpdateProfileAboutMutationResult = Apollo.MutationResult<UpdateProfileAboutMutation>;
|
||||
export type UpdateProfileAboutMutationOptions = Apollo.BaseMutationOptions<UpdateProfileAboutMutation, UpdateProfileAboutMutationVariables>;
|
||||
export type UpdateUserRolesSkillsMutationHookResult = ReturnType<typeof useUpdateUserRolesSkillsMutation>;
|
||||
export type UpdateUserRolesSkillsMutationResult = Apollo.MutationResult<UpdateUserRolesSkillsMutation>;
|
||||
export type UpdateUserRolesSkillsMutationOptions = Apollo.BaseMutationOptions<UpdateUserRolesSkillsMutation, UpdateUserRolesSkillsMutationVariables>;
|
||||
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
|
||||
@@ -1579,9 +1763,25 @@ export const ProfileDocument = gql`
|
||||
icon
|
||||
}
|
||||
}
|
||||
tournaments {
|
||||
id
|
||||
title
|
||||
thumbnail_image
|
||||
start_date
|
||||
end_date
|
||||
}
|
||||
similar_makers {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
jobTitle
|
||||
}
|
||||
...UserBasicInfo
|
||||
...UserRolesSkills
|
||||
}
|
||||
}
|
||||
`;
|
||||
${UserBasicInfoFragmentDoc}
|
||||
${UserRolesSkillsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useProfileQuery__
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { hackathons } from "./data/hackathon";
|
||||
import { posts, feed, generatePostComments } from "./data/posts";
|
||||
import { categories, projects } from "./data/projects";
|
||||
import { user } from "./data/users";
|
||||
import { allMakersRoles, allMakersSkills, user } from "./data/users";
|
||||
|
||||
export const MOCK_DATA = {
|
||||
projects,
|
||||
@@ -10,5 +10,7 @@ export const MOCK_DATA = {
|
||||
feed,
|
||||
hackathons,
|
||||
generatePostComments: generatePostComments,
|
||||
user: user
|
||||
user: user,
|
||||
allMakersRoles: allMakersRoles,
|
||||
allMakersSkills: allMakersSkills,
|
||||
}
|
||||
@@ -1,5 +1,101 @@
|
||||
import { MyProfile, User } from "src/graphql";
|
||||
import { Chance } from "chance";
|
||||
import { GenericMakerRole, MakerSkill, MyProfile, RoleLevelEnum, User } from "src/graphql";
|
||||
import { randomItem, randomItems } from "src/utils/helperFunctions";
|
||||
import { posts } from "./posts";
|
||||
import { getCoverImage, getAvatarImage } from "./utils";
|
||||
|
||||
const chance = new Chance();
|
||||
export const allMakersRoles: GenericMakerRole[] = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Frontend Dev",
|
||||
icon: "💄"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Backend Dev",
|
||||
icon: "💻️"
|
||||
}, {
|
||||
id: 3,
|
||||
title: "UI/UX Designer",
|
||||
icon: "🌈️️"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "Community Manager",
|
||||
icon: "🎉️️"
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "Founder",
|
||||
icon: "🦄️"
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: "Marketer",
|
||||
icon: "🚨️"
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
title: "Content Creator",
|
||||
icon: "🎥️"
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
title: "Researcher",
|
||||
icon: "🔬"
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
title: "Data engineer",
|
||||
icon: "💿️"
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
title: "Growth hacker",
|
||||
icon: "📉️"
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
title: "Technical Writer",
|
||||
icon: "✍️️"
|
||||
},
|
||||
]
|
||||
|
||||
export const allMakersSkills: MakerSkill[] = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Figma"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Prototyping"
|
||||
}, {
|
||||
id: 3,
|
||||
title: "Writing"
|
||||
}, {
|
||||
id: 4,
|
||||
title: "CSS"
|
||||
}, {
|
||||
id: 5,
|
||||
title: "React.js"
|
||||
}, {
|
||||
id: 6,
|
||||
title: "Wordpress"
|
||||
}, {
|
||||
id: 7,
|
||||
title: "Principle app"
|
||||
}, {
|
||||
id: 8,
|
||||
title: "UX design"
|
||||
}, {
|
||||
id: 9,
|
||||
title: "User research"
|
||||
}, {
|
||||
id: 10,
|
||||
title: "User testing"
|
||||
},
|
||||
]
|
||||
|
||||
export const user: User & MyProfile = {
|
||||
id: 123,
|
||||
@@ -25,8 +121,55 @@ export const user: User & MyProfile = {
|
||||
name: "My Alby wallet key"
|
||||
},
|
||||
{
|
||||
key: "6643534534534534543",
|
||||
key: "66345134234235",
|
||||
name: "My Phoenix wallet key"
|
||||
},],
|
||||
roles: randomItems(3, ...allMakersRoles).map(role => ({ ...role, level: randomItem(...Object.values(RoleLevelEnum)) })),
|
||||
skills: randomItems(7, ...allMakersSkills),
|
||||
tournaments: [
|
||||
{
|
||||
id: 1,
|
||||
title: "BreezConf",
|
||||
description: chance.paragraph(),
|
||||
cover_image: getCoverImage(),
|
||||
thumbnail_image: getCoverImage(),
|
||||
start_date: new Date(2021, 3).toISOString(),
|
||||
end_date: new Date(2021, 4).toISOString(),
|
||||
tags: [],
|
||||
website: "https://breez-conf.com"
|
||||
},
|
||||
]
|
||||
{
|
||||
id: 2,
|
||||
title: "Shock the Web 3",
|
||||
description: chance.paragraph(),
|
||||
cover_image: getCoverImage(),
|
||||
thumbnail_image: getCoverImage(),
|
||||
start_date: new Date(2022, 7).toISOString(),
|
||||
end_date: new Date(2022, 11).toISOString(),
|
||||
tags: [],
|
||||
website: "https://shock-the-web.com"
|
||||
},
|
||||
],
|
||||
similar_makers: [
|
||||
{
|
||||
id: 144,
|
||||
name: "Johns Beharry",
|
||||
jobTitle: "Manager",
|
||||
avatar: getAvatarImage(),
|
||||
},
|
||||
{
|
||||
id: 155,
|
||||
name: "Edward P",
|
||||
jobTitle: "Front-end Developer",
|
||||
avatar: getAvatarImage(),
|
||||
},
|
||||
{
|
||||
id: 166,
|
||||
name: "Mohammed T",
|
||||
jobTitle: "Front-end Developer",
|
||||
avatar: getAvatarImage(),
|
||||
},
|
||||
] as User[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
import { graphql } from 'msw'
|
||||
import { allCategories, getAllHackathons, getCategory, getFeed, getMyDrafts, getPostById, getProject, getTrendingPosts, hottestProjects, me, newProjects, popularTags, profile, projectsByCategory, searchProjects } from './resolvers'
|
||||
import { allCategories, getAllHackathons, getAllMakersRoles, getAllMakersSkills, getCategory, getFeed, getMyDrafts, getPostById, getProject, getTrendingPosts, hottestProjects, me, newProjects, popularTags, profile, projectsByCategory, searchProjects } from './resolvers'
|
||||
import {
|
||||
NavCategoriesQuery,
|
||||
ExploreProjectsQuery,
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
GetMyDraftsQuery,
|
||||
MyProfileAboutQuery,
|
||||
MyProfilePreferencesQuery,
|
||||
MyProfileRolesSkillsQuery,
|
||||
} from 'src/graphql'
|
||||
|
||||
const delay = (ms = 1000) => new Promise((res) => setTimeout(res, ms + Math.random() * 1000))
|
||||
@@ -197,8 +198,6 @@ export const handlers = [
|
||||
|
||||
graphql.query<MeQuery>('Me', async (req, res, ctx) => {
|
||||
await delay()
|
||||
console.log("ME");
|
||||
|
||||
return res(
|
||||
ctx.data({
|
||||
me: me()
|
||||
@@ -226,6 +225,17 @@ export const handlers = [
|
||||
}),
|
||||
|
||||
|
||||
graphql.query<MyProfileRolesSkillsQuery>('MyProfileRolesSkills', async (req, res, ctx) => {
|
||||
await delay()
|
||||
return res(
|
||||
ctx.data({
|
||||
me: { ...me() },
|
||||
getAllMakersRoles: getAllMakersRoles(),
|
||||
getAllMakersSkills: getAllMakersSkills(),
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
|
||||
graphql.query<ProfileQuery>('profile', async (req, res, ctx) => {
|
||||
await delay()
|
||||
|
||||
@@ -84,6 +84,13 @@ export function profile() {
|
||||
return { ...MOCK_DATA['user'], __typename: 'User' } as User
|
||||
}
|
||||
|
||||
export function getAllMakersRoles() {
|
||||
return MOCK_DATA['allMakersRoles']
|
||||
}
|
||||
|
||||
export function getAllMakersSkills() {
|
||||
return MOCK_DATA['allMakersSkills']
|
||||
}
|
||||
export function getMyDrafts(): Query['getMyDrafts'] {
|
||||
return MOCK_DATA['posts'].stories;
|
||||
}
|
||||
@@ -8,8 +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/PreferencesTab/LinkingAccountModal";
|
||||
import { RemoveWalletKeyModal } from "src/features/Profiles/pages/EditProfilePage/PreferencesTab/RemoveWalletKeyModal";
|
||||
import { LinkingAccountModal } from "src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkingAccountModal";
|
||||
|
||||
import { ComponentProps } from "react";
|
||||
import { generateId } from "src/utils/helperFunctions";
|
||||
|
||||
@@ -49,6 +49,9 @@ export const apolloClient = new ApolloClient({
|
||||
httpLink
|
||||
]),
|
||||
cache: new InMemoryCache({
|
||||
possibleTypes: {
|
||||
BaseUser: ['User', 'MyProfile']
|
||||
},
|
||||
typePolicies: {
|
||||
Query: {
|
||||
fields: {
|
||||
|
||||
Reference in New Issue
Block a user