mirror of
https://github.com/aljazceru/landscape-template.git
synced 2026-01-31 12:14:30 +01:00
fix: fixing pre-launch issues
- refactor the tags topics stuff (apis/mocks/components) - update TagsInput - Change how feed page looks on tags filtering
This commit is contained in:
@@ -34,7 +34,6 @@ export interface NexusGenInputs {
|
||||
id?: number | null; // Int
|
||||
tags: string[]; // [String!]!
|
||||
title: string; // String!
|
||||
topicId: number; // Int!
|
||||
}
|
||||
UpdateProfileInput: { // input type
|
||||
avatar?: string | null; // String
|
||||
@@ -174,12 +173,9 @@ export interface NexusGenObjects {
|
||||
votes_count: number; // Int!
|
||||
}
|
||||
Tag: { // root type
|
||||
icon?: string | null; // String
|
||||
id: number; // Int!
|
||||
title: string; // String!
|
||||
}
|
||||
Topic: { // root type
|
||||
icon: string; // String!
|
||||
id: number; // Int!
|
||||
isOfficial?: boolean | null; // Boolean
|
||||
title: string; // String!
|
||||
}
|
||||
User: { // root type
|
||||
@@ -288,8 +284,8 @@ export interface NexusGenFieldTypes {
|
||||
id: number; // Int!
|
||||
location: string; // String!
|
||||
start_date: NexusGenScalars['Date']; // Date!
|
||||
tags: NexusGenRootTypes['Tag'][]; // [Tag!]!
|
||||
title: string; // String!
|
||||
topics: NexusGenRootTypes['Topic'][]; // [Topic!]!
|
||||
website: string; // String!
|
||||
}
|
||||
LnurlDetails: { // field return type
|
||||
@@ -333,7 +329,6 @@ export interface NexusGenFieldTypes {
|
||||
Query: { // field return type
|
||||
allCategories: NexusGenRootTypes['Category'][]; // [Category!]!
|
||||
allProjects: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
allTopics: NexusGenRootTypes['Topic'][]; // [Topic!]!
|
||||
getAllHackathons: NexusGenRootTypes['Hackathon'][]; // [Hackathon!]!
|
||||
getCategory: NexusGenRootTypes['Category']; // Category!
|
||||
getDonationsStats: NexusGenRootTypes['DonationsStats']; // DonationsStats!
|
||||
@@ -345,7 +340,8 @@ export interface NexusGenFieldTypes {
|
||||
hottestProjects: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
me: NexusGenRootTypes['User'] | null; // User
|
||||
newProjects: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
popularTopics: NexusGenRootTypes['Topic'][]; // [Topic!]!
|
||||
officialTags: NexusGenRootTypes['Tag'][]; // [Tag!]!
|
||||
popularTags: NexusGenRootTypes['Tag'][]; // [Tag!]!
|
||||
profile: NexusGenRootTypes['User'] | null; // User
|
||||
projectsByCategory: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
searchProjects: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
@@ -374,17 +370,13 @@ export interface NexusGenFieldTypes {
|
||||
id: number; // Int!
|
||||
tags: NexusGenRootTypes['Tag'][]; // [Tag!]!
|
||||
title: string; // String!
|
||||
topic: NexusGenRootTypes['Topic']; // Topic!
|
||||
type: string; // String!
|
||||
votes_count: number; // Int!
|
||||
}
|
||||
Tag: { // field return type
|
||||
icon: string | null; // String
|
||||
id: number; // Int!
|
||||
title: string; // String!
|
||||
}
|
||||
Topic: { // field return type
|
||||
icon: string; // String!
|
||||
id: number; // Int!
|
||||
isOfficial: boolean | null; // Boolean
|
||||
title: string; // String!
|
||||
}
|
||||
User: { // field return type
|
||||
@@ -489,8 +481,8 @@ export interface NexusGenFieldTypeNames {
|
||||
id: 'Int'
|
||||
location: 'String'
|
||||
start_date: 'Date'
|
||||
tags: 'Tag'
|
||||
title: 'String'
|
||||
topics: 'Topic'
|
||||
website: 'String'
|
||||
}
|
||||
LnurlDetails: { // field return type name
|
||||
@@ -534,7 +526,6 @@ export interface NexusGenFieldTypeNames {
|
||||
Query: { // field return type name
|
||||
allCategories: 'Category'
|
||||
allProjects: 'Project'
|
||||
allTopics: 'Topic'
|
||||
getAllHackathons: 'Hackathon'
|
||||
getCategory: 'Category'
|
||||
getDonationsStats: 'DonationsStats'
|
||||
@@ -546,7 +537,8 @@ export interface NexusGenFieldTypeNames {
|
||||
hottestProjects: 'Project'
|
||||
me: 'User'
|
||||
newProjects: 'Project'
|
||||
popularTopics: 'Topic'
|
||||
officialTags: 'Tag'
|
||||
popularTags: 'Tag'
|
||||
profile: 'User'
|
||||
projectsByCategory: 'Project'
|
||||
searchProjects: 'Project'
|
||||
@@ -575,17 +567,13 @@ export interface NexusGenFieldTypeNames {
|
||||
id: 'Int'
|
||||
tags: 'Tag'
|
||||
title: 'String'
|
||||
topic: 'Topic'
|
||||
type: 'String'
|
||||
votes_count: 'Int'
|
||||
}
|
||||
Tag: { // field return type name
|
||||
id: 'Int'
|
||||
title: 'String'
|
||||
}
|
||||
Topic: { // field return type name
|
||||
icon: 'String'
|
||||
id: 'Int'
|
||||
isOfficial: 'Boolean'
|
||||
title: 'String'
|
||||
}
|
||||
User: { // field return type name
|
||||
@@ -658,7 +646,7 @@ export interface NexusGenArgTypes {
|
||||
}
|
||||
getAllHackathons: { // args
|
||||
sortBy?: string | null; // String
|
||||
topic?: number | null; // Int
|
||||
tag?: number | null; // Int
|
||||
}
|
||||
getCategory: { // args
|
||||
id: number; // Int!
|
||||
@@ -666,8 +654,8 @@ export interface NexusGenArgTypes {
|
||||
getFeed: { // args
|
||||
skip?: number | null; // Int
|
||||
sortBy?: string | null; // String
|
||||
tag?: number | null; // Int
|
||||
take: number | null; // Int
|
||||
topic?: number | null; // Int
|
||||
}
|
||||
getLnurlDetailsForProject: { // args
|
||||
project_id: number; // Int!
|
||||
|
||||
@@ -78,8 +78,8 @@ type Hackathon {
|
||||
id: Int!
|
||||
location: String!
|
||||
start_date: Date!
|
||||
tags: [Tag!]!
|
||||
title: String!
|
||||
topics: [Topic!]!
|
||||
website: String!
|
||||
}
|
||||
|
||||
@@ -145,11 +145,10 @@ type Project {
|
||||
type Query {
|
||||
allCategories: [Category!]!
|
||||
allProjects(skip: Int = 0, take: Int = 50): [Project!]!
|
||||
allTopics: [Topic!]!
|
||||
getAllHackathons(sortBy: String, topic: Int): [Hackathon!]!
|
||||
getAllHackathons(sortBy: String, tag: Int): [Hackathon!]!
|
||||
getCategory(id: Int!): Category!
|
||||
getDonationsStats: DonationsStats!
|
||||
getFeed(skip: Int = 0, sortBy: String, take: Int = 10, topic: Int = 0): [Post!]!
|
||||
getFeed(skip: Int = 0, sortBy: String, tag: Int = 0, take: Int = 10): [Post!]!
|
||||
getLnurlDetailsForProject(project_id: Int!): LnurlDetails!
|
||||
getPostById(id: Int!, type: POST_TYPE!): Post!
|
||||
getProject(id: Int!): Project!
|
||||
@@ -157,7 +156,8 @@ type Query {
|
||||
hottestProjects(skip: Int = 0, take: Int = 50): [Project!]!
|
||||
me: User
|
||||
newProjects(skip: Int = 0, take: Int = 50): [Project!]!
|
||||
popularTopics: [Topic!]!
|
||||
officialTags: [Tag!]!
|
||||
popularTags: [Tag!]!
|
||||
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!]!
|
||||
@@ -188,7 +188,6 @@ type Story implements PostBase {
|
||||
id: Int!
|
||||
tags: [Tag!]!
|
||||
title: String!
|
||||
topic: Topic!
|
||||
type: String!
|
||||
votes_count: Int!
|
||||
}
|
||||
@@ -199,17 +198,12 @@ input StoryInputType {
|
||||
id: Int
|
||||
tags: [String!]!
|
||||
title: String!
|
||||
topicId: Int!
|
||||
}
|
||||
|
||||
type Tag {
|
||||
icon: String
|
||||
id: Int!
|
||||
title: String!
|
||||
}
|
||||
|
||||
type Topic {
|
||||
icon: String!
|
||||
id: Int!
|
||||
isOfficial: Boolean
|
||||
title: String!
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ const Hackathon = objectType({
|
||||
t.nonNull.date('end_date');
|
||||
t.nonNull.string('location');
|
||||
t.nonNull.string('website');
|
||||
t.nonNull.list.nonNull.field('topics', {
|
||||
type: "Topic",
|
||||
t.nonNull.list.nonNull.field('tags', {
|
||||
type: "Tag",
|
||||
resolve: (parent) => {
|
||||
return prisma.hackathon.findUnique({ where: { id: parent.id } }).topics();
|
||||
return prisma.hackathon.findUnique({ where: { id: parent.id } }).tags();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -36,10 +36,10 @@ const getAllHackathons = extendType({
|
||||
type: "Hackathon",
|
||||
args: {
|
||||
sortBy: stringArg(),
|
||||
topic: intArg(),
|
||||
tag: intArg(),
|
||||
},
|
||||
resolve(_, args) {
|
||||
const { sortBy, topic } = args;
|
||||
const { sortBy, tag } = args;
|
||||
return prisma.hackathon.findMany({
|
||||
where: {
|
||||
...(sortBy === 'Upcoming' && {
|
||||
@@ -57,10 +57,12 @@ const getAllHackathons = extendType({
|
||||
}
|
||||
}),
|
||||
|
||||
...(topic && {
|
||||
topics: {
|
||||
|
||||
|
||||
...(tag && {
|
||||
tags: {
|
||||
some: {
|
||||
id: topic
|
||||
id: tag
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -6,8 +6,10 @@ const post = require('./post')
|
||||
const users = require('./users')
|
||||
const hackathon = require('./hackathon')
|
||||
const donation = require('./donation')
|
||||
const tag = require('./tag')
|
||||
|
||||
module.exports = {
|
||||
...tag,
|
||||
...scalars,
|
||||
...category,
|
||||
...project,
|
||||
|
||||
@@ -32,15 +32,6 @@ const asQuestionType = asType('Question')
|
||||
const asBountyType = asType('Bounty')
|
||||
|
||||
|
||||
const Topic = objectType({
|
||||
name: 'Topic',
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
t.nonNull.string('title');
|
||||
t.nonNull.string('icon');
|
||||
}
|
||||
})
|
||||
|
||||
const Author = objectType({
|
||||
name: 'Author',
|
||||
definition(t) {
|
||||
@@ -52,39 +43,7 @@ const Author = objectType({
|
||||
})
|
||||
|
||||
|
||||
const allTopics = extendType({
|
||||
type: "Query",
|
||||
definition(t) {
|
||||
t.nonNull.list.nonNull.field('allTopics', {
|
||||
type: "Topic",
|
||||
resolve: () => {
|
||||
return prisma.topic.findMany({
|
||||
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const popularTopics = extendType({
|
||||
type: "Query",
|
||||
definition(t) {
|
||||
t.nonNull.list.nonNull.field('popularTopics', {
|
||||
type: "Topic",
|
||||
resolve: () => {
|
||||
return prisma.topic.findMany({
|
||||
take: 6,
|
||||
orderBy: {
|
||||
stories: {
|
||||
_count: 'desc'
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const PostBase = interfaceType({
|
||||
name: 'PostBase',
|
||||
@@ -132,14 +91,6 @@ const Story = objectType({
|
||||
return post._count.comments;
|
||||
}
|
||||
});
|
||||
t.nonNull.field('topic', {
|
||||
type: "Topic",
|
||||
resolve: parent => {
|
||||
return prisma.story.findUnique({
|
||||
where: { id: parent.id }
|
||||
}).topic()
|
||||
}
|
||||
})
|
||||
t.nonNull.field('author', {
|
||||
type: "Author",
|
||||
resolve: (parent) =>
|
||||
@@ -158,7 +109,6 @@ const StoryInputType = inputObjectType({
|
||||
t.nonNull.string('body');
|
||||
t.nonNull.string('cover_image');
|
||||
t.nonNull.list.nonNull.string('tags');
|
||||
t.nonNull.int('topicId');
|
||||
}
|
||||
})
|
||||
const createStory = extendType({
|
||||
@@ -168,7 +118,7 @@ const createStory = extendType({
|
||||
type: 'Story',
|
||||
args: { data: StoryInputType },
|
||||
async resolve(_root, args, ctx) {
|
||||
const { id, title, body, cover_image, tags, topicId } = args.data;
|
||||
const { id, title, body, cover_image, tags } = args.data;
|
||||
const user = await getUserByPubKey(ctx.userPubKey);
|
||||
|
||||
// Do some validation
|
||||
@@ -215,11 +165,6 @@ const createStory = extendType({
|
||||
}
|
||||
})
|
||||
},
|
||||
topic: {
|
||||
connect: {
|
||||
id: topicId
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
@@ -244,11 +189,6 @@ const createStory = extendType({
|
||||
}
|
||||
})
|
||||
},
|
||||
topic: {
|
||||
connect: {
|
||||
id: topicId
|
||||
}
|
||||
},
|
||||
user: {
|
||||
connect: {
|
||||
id: user.id,
|
||||
@@ -398,11 +338,11 @@ const getFeed = extendType({
|
||||
args: {
|
||||
...paginationArgs({ take: 10 }),
|
||||
sortBy: stringArg(), // all, popular, trending, newest
|
||||
topic: intArg({
|
||||
tag: intArg({
|
||||
default: 0
|
||||
})
|
||||
},
|
||||
resolve(_, { take, skip, topic, sortBy, }) {
|
||||
resolve(_, { take, skip, tag, sortBy, }) {
|
||||
|
||||
|
||||
let orderBy = { createdAt: "desc" };
|
||||
@@ -415,7 +355,13 @@ const getFeed = extendType({
|
||||
return prisma.story.findMany({
|
||||
orderBy: orderBy,
|
||||
where: {
|
||||
topic_id: topic ? topic : undefined,
|
||||
...(tag && {
|
||||
tags: {
|
||||
some: {
|
||||
id: tag
|
||||
}
|
||||
},
|
||||
})
|
||||
},
|
||||
skip,
|
||||
take,
|
||||
@@ -485,7 +431,6 @@ module.exports = {
|
||||
// Types
|
||||
POST_TYPE,
|
||||
Author,
|
||||
Topic,
|
||||
PostBase,
|
||||
BountyApplication,
|
||||
Bounty,
|
||||
@@ -495,8 +440,6 @@ module.exports = {
|
||||
PostComment,
|
||||
Post,
|
||||
// Queries
|
||||
allTopics,
|
||||
popularTopics,
|
||||
getFeed,
|
||||
getPostById,
|
||||
getTrendingPosts,
|
||||
|
||||
@@ -64,19 +64,7 @@ const Award = objectType({
|
||||
}
|
||||
})
|
||||
|
||||
const Tag = objectType({
|
||||
name: 'Tag',
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
t.nonNull.string('title');
|
||||
// t.nonNull.list.nonNull.field('project', {
|
||||
// type: "Project",
|
||||
// resolve: (parent) => {
|
||||
// return prisma.tag.findUnique({ where: { id: parent.id } }).project();
|
||||
// }
|
||||
// })
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
const getProject = extendType({
|
||||
@@ -255,7 +243,6 @@ module.exports = {
|
||||
// Types
|
||||
Project,
|
||||
Award,
|
||||
Tag,
|
||||
// Queries
|
||||
getProject,
|
||||
allProjects,
|
||||
|
||||
59
api/functions/graphql/types/tag.js
Normal file
59
api/functions/graphql/types/tag.js
Normal file
@@ -0,0 +1,59 @@
|
||||
const { objectType, extendType } = require("nexus");
|
||||
const { prisma } = require('../../../prisma');
|
||||
|
||||
const Tag = objectType({
|
||||
name: 'Tag',
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
t.nonNull.string('title');
|
||||
t.string('icon');
|
||||
t.boolean('isOfficial');
|
||||
}
|
||||
});
|
||||
|
||||
const officialTags = extendType({
|
||||
type: "Query",
|
||||
definition(t) {
|
||||
t.nonNull.list.nonNull.field('officialTags', {
|
||||
type: "Tag",
|
||||
resolve: () => {
|
||||
return prisma.tag.findMany({
|
||||
where: {
|
||||
isOfficial: true
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const popularTags = extendType({
|
||||
type: "Query",
|
||||
definition(t) {
|
||||
t.nonNull.list.nonNull.field('popularTags', {
|
||||
type: "Tag",
|
||||
resolve: () => {
|
||||
return prisma.tag.findMany({
|
||||
where: {
|
||||
isOfficial: true
|
||||
},
|
||||
take: 8,
|
||||
orderBy: {
|
||||
stories: {
|
||||
_count: 'desc'
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
// Types
|
||||
Tag,
|
||||
|
||||
// Queries
|
||||
popularTags,
|
||||
officialTags,
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `Topic` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `_HackathonToTopic` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Question" DROP CONSTRAINT "Question_topic_id_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Story" DROP CONSTRAINT "Story_topic_id_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_HackathonToTopic" DROP CONSTRAINT "_HackathonToTopic_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_HackathonToTopic" DROP CONSTRAINT "_HackathonToTopic_B_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Tag" ADD COLUMN "icon" TEXT,
|
||||
ADD COLUMN "isOfficial" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "Topic";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_HackathonToTopic";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_HackathonToTag" (
|
||||
"A" INTEGER NOT NULL,
|
||||
"B" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "_HackathonToTag_AB_unique" ON "_HackathonToTag"("A", "B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_HackathonToTag_B_index" ON "_HackathonToTag"("B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_HackathonToTag" ADD FOREIGN KEY ("A") REFERENCES "Hackathon"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_HackathonToTag" ADD FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `topic_id` on the `Question` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `topic_id` on the `Story` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Question" DROP COLUMN "topic_id";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Story" DROP COLUMN "topic_id";
|
||||
@@ -12,12 +12,15 @@ generator client {
|
||||
// -----------------
|
||||
|
||||
model Tag {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @unique
|
||||
id Int @id @default(autoincrement())
|
||||
title String @unique
|
||||
icon String?
|
||||
isOfficial Boolean @default(false)
|
||||
|
||||
project Project[]
|
||||
stories Story[]
|
||||
questions Question[]
|
||||
project Project[]
|
||||
stories Story[]
|
||||
questions Question[]
|
||||
hackathons Hackathon[]
|
||||
}
|
||||
|
||||
model Vote {
|
||||
@@ -119,8 +122,6 @@ model Story {
|
||||
cover_image String
|
||||
votes_count Int @default(0)
|
||||
|
||||
topic Topic @relation(fields: [topic_id], references: [id])
|
||||
topic_id Int
|
||||
|
||||
tags Tag[]
|
||||
|
||||
@@ -139,8 +140,6 @@ model Question {
|
||||
excerpt String
|
||||
votes_count Int @default(0)
|
||||
|
||||
topic Topic @relation(fields: [topic_id], references: [id])
|
||||
topic_id Int
|
||||
|
||||
tags Tag[]
|
||||
|
||||
@@ -150,16 +149,6 @@ model Question {
|
||||
comments PostComment[] @relation("QuestionComment")
|
||||
}
|
||||
|
||||
model Topic {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @unique
|
||||
icon String
|
||||
|
||||
stories Story[]
|
||||
questions Question[]
|
||||
hackathons Hackathon[]
|
||||
}
|
||||
|
||||
model PostComment {
|
||||
id Int @id @default(autoincrement())
|
||||
body String
|
||||
@@ -196,7 +185,7 @@ model Hackathon {
|
||||
website String
|
||||
votes_count Int @default(0)
|
||||
|
||||
topics Topic[]
|
||||
tags Tag[]
|
||||
}
|
||||
|
||||
// -----------------
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { MdClose } from 'react-icons/md';
|
||||
import IconButton from 'src/Components/IconButton/IconButton';
|
||||
import { useMemo } from 'react'
|
||||
import FileThumbnail from './FileThumbnail';
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import { motion } from "framer-motion";
|
||||
import { useState } from "react";
|
||||
|
||||
import { useController } from "react-hook-form";
|
||||
import Badge from "src/Components/Badge/Badge";
|
||||
import { Tag as ApiTag } from "src/utils/interfaces";
|
||||
import CreatableSelect from 'react-select/creatable';
|
||||
import { OnChangeValue, StylesConfig, components, OptionProps } from "react-select";
|
||||
import { useOfficialTagsQuery } from "src/graphql";
|
||||
|
||||
type Tag = Pick<ApiTag, 'title'>
|
||||
interface Option {
|
||||
readonly label: string;
|
||||
readonly value: string;
|
||||
readonly icon: string | null
|
||||
}
|
||||
|
||||
type Tag = {
|
||||
title: string,
|
||||
icon: string | null
|
||||
}
|
||||
|
||||
interface Props {
|
||||
classes?: {
|
||||
@@ -17,6 +27,46 @@ interface Props {
|
||||
}
|
||||
|
||||
|
||||
const transformer = {
|
||||
tagToOption: (tag: Tag): Option => ({ label: tag.title, value: tag.title, icon: tag.icon }),
|
||||
optionToTag: (o: Option): Tag => ({ title: o.value, icon: null })
|
||||
}
|
||||
|
||||
const OptionComponent = (props: OptionProps<Option>) => {
|
||||
return (
|
||||
<div>
|
||||
<components.Option {...props} className='flex items-start'>
|
||||
<span className={`rounded-8 w-40 h-40 text-center py-8`}>
|
||||
{props.data.icon}
|
||||
</span>
|
||||
<span className="self-center px-16">
|
||||
{props.data.label}
|
||||
</span>
|
||||
</components.Option>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const colourStyles: StylesConfig = {
|
||||
|
||||
control: (styles, state) => ({
|
||||
...styles,
|
||||
padding: '1px 4px',
|
||||
borderRadius: 8,
|
||||
}),
|
||||
indicatorSeparator: (styles, state) => ({
|
||||
...styles,
|
||||
display: "none"
|
||||
}),
|
||||
input: (styles, state) => ({
|
||||
...styles,
|
||||
" input": {
|
||||
boxShadow: 'none !important'
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
|
||||
export default function TagsInput({
|
||||
classes,
|
||||
@@ -24,20 +74,20 @@ export default function TagsInput({
|
||||
max = 5,
|
||||
...props }: Props) {
|
||||
|
||||
|
||||
const [inputText, setInputText] = useState("");
|
||||
const officalTags = useOfficialTagsQuery();
|
||||
|
||||
const { field: { value, onChange, onBlur } } = useController({
|
||||
name: props.name ?? "tags",
|
||||
control: props.control,
|
||||
})
|
||||
|
||||
const handleSubmit = () => {
|
||||
onChange([...value, { title: inputText }]);
|
||||
setInputText('');
|
||||
|
||||
const handleChange = (newValue: OnChangeValue<Option, true>,) => {
|
||||
onChange([...value, ...newValue.map(transformer.optionToTag)]);
|
||||
onBlur();
|
||||
}
|
||||
|
||||
|
||||
const handleRemove = (idx: number) => {
|
||||
onChange((value as Tag[]).filter((_, i) => idx !== i))
|
||||
onBlur();
|
||||
@@ -45,35 +95,37 @@ export default function TagsInput({
|
||||
|
||||
const isDisabled = value.length >= max;
|
||||
|
||||
const tagsOptions = (officalTags.data?.officialTags ?? []).filter(t => !value.some((v: Tag) => v.title === t.title)).map(transformer.tagToOption);
|
||||
|
||||
return (
|
||||
<div className={`${classes?.container}`}>
|
||||
<div className="input-wrapper relative">
|
||||
<input
|
||||
disabled={isDisabled}
|
||||
type='text'
|
||||
className={`input-text inline-block
|
||||
${isDisabled && 'opacity-50'}
|
||||
${classes?.input}`}
|
||||
placeholder={placeholder}
|
||||
value={inputText}
|
||||
onChange={(e) => setInputText(e.target.value)}
|
||||
onKeyPress={e => {
|
||||
if (e.key === 'Enter' && inputText.trim().length > 1) { e.preventDefault(); handleSubmit() }
|
||||
}}
|
||||
/>
|
||||
{inputText.length > 2 && <motion.span
|
||||
initial={{ scale: 1, y: "-50%" }}
|
||||
animate={{ scale: 1.05 }}
|
||||
transition={{
|
||||
repeat: Infinity,
|
||||
repeatType: 'mirror',
|
||||
duration: .9
|
||||
}}
|
||||
className="text-gray-500 absolute top-1/2 right-16">
|
||||
Enter to Insert
|
||||
</motion.span>}
|
||||
</div>
|
||||
<CreatableSelect
|
||||
isLoading={officalTags.loading}
|
||||
options={tagsOptions}
|
||||
isMulti
|
||||
isDisabled={isDisabled}
|
||||
placeholder={placeholder}
|
||||
isClearable
|
||||
|
||||
|
||||
value={[]}
|
||||
onChange={handleChange as any}
|
||||
onBlur={onBlur}
|
||||
components={{
|
||||
Option: OptionComponent,
|
||||
MultiValue: () => <></>
|
||||
}}
|
||||
|
||||
styles={colourStyles as any}
|
||||
theme={(theme) => ({
|
||||
...theme,
|
||||
borderRadius: 8,
|
||||
colors: {
|
||||
...theme.colors,
|
||||
primary: 'var(--primary)',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
<div className="flex mt-16 gap-8 flex-wrap">
|
||||
{(value as Tag[]).map((tag, idx) => <Badge color="gray" key={tag.title} onRemove={() => handleRemove(idx)} >{tag.title}</Badge>)}
|
||||
</div>
|
||||
|
||||
7
src/Components/Inputs/TagsInput/officalTags.graphql
Normal file
7
src/Components/Inputs/TagsInput/officalTags.graphql
Normal file
@@ -0,0 +1,7 @@
|
||||
query OfficialTags {
|
||||
officialTags {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,11 @@
|
||||
import NavMobile from "./NavMobile";
|
||||
import { MdComment, MdHomeFilled, MdLocalFireDepartment } from "react-icons/md";
|
||||
import { IoExtensionPuzzle } from "react-icons/io5";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useAppDispatch, useAppSelector, useMediaQuery } from "src/utils/hooks";
|
||||
import { openModal } from "src/redux/features/modals.slice";
|
||||
import { useEffect, } from "react";
|
||||
import { useAppDispatch, useMediaQuery } from "src/utils/hooks";
|
||||
import { setNavHeight } from "src/redux/features/ui.slice";
|
||||
import NavDesktop from "./NavDesktop";
|
||||
import { MEDIA_QUERIES } from "src/utils/theme/media_queries";
|
||||
import { IoMdTrophy } from "react-icons/io";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useMeQuery } from "src/graphql";
|
||||
import { setUser } from "src/redux/features/user.slice";
|
||||
|
||||
|
||||
export const navLinks = [
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
import { openModal } from 'src/redux/features/modals.slice';
|
||||
import { openProject } from 'src/redux/features/project.slice';
|
||||
import { useAppDispatch } from 'src/utils/hooks';
|
||||
import { ProjectSearchItem } from '../Search';
|
||||
import SearchProjectCard from '../SearchProjectCard/SearchProjectCard';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PropsWithChildren } from "react";
|
||||
import { Navigate, Outlet } from "react-router-dom";
|
||||
import { Navigate, } from "react-router-dom";
|
||||
import { useAppSelector } from "src/utils/hooks";
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -4,9 +4,18 @@ import Button from "src/Components/Button/Button"
|
||||
import dayjs from "dayjs";
|
||||
import advancedFormat from 'dayjs/plugin/advancedFormat'
|
||||
import { trimText } from "src/utils/helperFunctions";
|
||||
import { Override } from "src/utils/interfaces";
|
||||
import { Tag } from "src/graphql";
|
||||
dayjs.extend(advancedFormat)
|
||||
|
||||
export type HackathonCardType = Hackathon;
|
||||
export type HackathonCardType = Override<Hackathon,
|
||||
{
|
||||
tags: Pick<Tag,
|
||||
| 'id'
|
||||
| 'title'
|
||||
| 'icon'>[]
|
||||
}
|
||||
>;
|
||||
|
||||
interface Props {
|
||||
hackathon: HackathonCardType
|
||||
@@ -32,7 +41,7 @@ export default function HackathonCard({ hackathon }: Props) {
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-16 flex flex-wrap gap-8">
|
||||
{hackathon.topics.map(topic => <div key={topic.id} className="p-8 bg-gray-50 rounded-8 text-body5">{topic.icon} {topic.title}</div>)}
|
||||
{hackathon.tags.map(tag => <div key={tag.id} className="p-8 bg-gray-50 rounded-8 text-body5">{tag.icon} {tag.title}</div>)}
|
||||
</div>
|
||||
<div className="mt-auto"></div>
|
||||
<Button href={hackathon.website} newTab color="gray" fullWidth className="mt-16">
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import TopicsFilter from './TopicsFilter';
|
||||
|
||||
export default {
|
||||
title: 'Hackathons/Components/Filters/Topics',
|
||||
component: TopicsFilter,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
} as ComponentMeta<typeof TopicsFilter>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof TopicsFilter> = (args) => <div className="max-w-[326px]"><TopicsFilter {...args as any} ></TopicsFilter></div>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import { useMediaQuery } from 'src/utils/hooks';
|
||||
import React, { useState } from 'react'
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import Slider from 'src/Components/Slider/Slider';
|
||||
import { useAllTopicsQuery, usePopularTopicsQuery } from 'src/graphql';
|
||||
import { MEDIA_QUERIES } from 'src/utils/theme';
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
filterChanged?: (newFilter: number | null) => void
|
||||
}
|
||||
|
||||
export default function PopularTopicsFilter({ filterChanged }: Props) {
|
||||
|
||||
const [selected, setSelected] = useState<number | null>(null);
|
||||
|
||||
const topicsQuery = useAllTopicsQuery();
|
||||
|
||||
|
||||
const filterClicked = (_newValue: number) => {
|
||||
const newValue = selected !== _newValue ? _newValue : null;
|
||||
setSelected(newValue);
|
||||
filterChanged?.(newValue);
|
||||
}
|
||||
|
||||
const isMdScreen = useMediaQuery(MEDIA_QUERIES.isMedium)
|
||||
|
||||
return (
|
||||
<div className='overflow-hidden'>
|
||||
{isMdScreen ?
|
||||
<div className='bg-white border-2 rounded-12 p-16 overflow-hidden'>
|
||||
<p className="text-body2 font-bolder text-black mb-16">Topics</p>
|
||||
<ul className=' flex flex-col gap-16'>
|
||||
{topicsQuery.loading ?
|
||||
Array(3).fill(0).map((_, idx) => <li
|
||||
key={idx}
|
||||
className={`flex items-start rounded-8 font-bold`}
|
||||
|
||||
>
|
||||
<span className='bg-gray-50 rounded-8 w-40 h-40 text-center py-8'> </span>
|
||||
<span className="self-center px-16"><Skeleton width={'7ch'} />
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
:
|
||||
topicsQuery.data?.allTopics.map((topic, idx) => <li
|
||||
key={topic.id}
|
||||
className={`flex items-start rounded-8 cursor-pointer font-bold
|
||||
active:scale-95 transition-transform
|
||||
${topic.id === selected ? 'bg-gray-200' : 'hover:bg-gray-100'}`}
|
||||
onClick={() => filterClicked(topic.id)}
|
||||
role='button'
|
||||
>
|
||||
<span className={`${topic.id !== selected && 'bg-gray-50'} rounded-8 w-40 h-40 text-center py-8`}>{topic.icon}</span>
|
||||
<span className="self-center px-16">
|
||||
{topic.title}
|
||||
</span>
|
||||
</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
:
|
||||
<>
|
||||
{
|
||||
topicsQuery.loading ?
|
||||
<ul className="flex gap-8 ">
|
||||
{Array(4).fill(0).map((_, idx) => <div key={idx} className="py-12 px-16 bg-gray-100 rounded-8 text-body5"><span className="opacity-0">Category</span></div>)}
|
||||
</ul>
|
||||
:
|
||||
<Slider>
|
||||
{topicsQuery.data?.allTopics.map(topic =>
|
||||
<div
|
||||
key={topic.id}
|
||||
onClick={() => filterClicked(topic.id)}
|
||||
className={`${topic.id === selected ? 'bg-gray-200' : "bg-gray-100"} py-12 px-16 rounded-8 text-body5`}
|
||||
>{topic.icon} {topic.title}</div>)}
|
||||
</Slider>
|
||||
}
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
query allTopics {
|
||||
allTopics {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,12 @@ import { Helmet } from 'react-helmet'
|
||||
export default function HackathonsPage() {
|
||||
|
||||
const [sortByFilter, setSortByFilter] = useState<string | null>('Upcoming')
|
||||
const [topicsFilter, setTopicsFilter] = useState<number | null>(null)
|
||||
const [tagFilter, setTagFilter] = useState<number | null>(null)
|
||||
|
||||
const hackathonsQuery = useGetHackathonsQuery({
|
||||
variables: {
|
||||
sortBy: sortByFilter,
|
||||
topic: Number(topicsFilter)
|
||||
tag: Number(tagFilter)
|
||||
},
|
||||
})
|
||||
const { navHeight } = useAppSelector((state) => ({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
query getHackathons($sortBy: String, $topic: Int) {
|
||||
getAllHackathons(sortBy: $sortBy, topic: $topic) {
|
||||
query getHackathons($sortBy: String, $tag: Int) {
|
||||
getAllHackathons(sortBy: $sortBy, tag: $tag) {
|
||||
id
|
||||
title
|
||||
description
|
||||
@@ -8,7 +8,7 @@ query getHackathons($sortBy: String, $topic: Int) {
|
||||
end_date
|
||||
location
|
||||
website
|
||||
topics {
|
||||
tags {
|
||||
id
|
||||
title
|
||||
icon
|
||||
|
||||
@@ -6,6 +6,7 @@ import Badge from "src/Components/Badge/Badge"
|
||||
import Button from "src/Components/Button/Button"
|
||||
import { Link } from "react-router-dom"
|
||||
import VoteButton from "src/Components/VoteButton/VoteButton"
|
||||
import { Tag } from "src/graphql"
|
||||
|
||||
export type BountyCardType = Pick<Bounty,
|
||||
| 'id'
|
||||
@@ -17,9 +18,10 @@ export type BountyCardType = Pick<Bounty,
|
||||
| 'excerpt'
|
||||
| 'votes_count'
|
||||
| "reward_amount"
|
||||
| "tags"
|
||||
| "applicants_count"
|
||||
>;
|
||||
> & {
|
||||
tags: Array<Pick<Tag, 'id' | "title">>
|
||||
};
|
||||
interface Props {
|
||||
bounty: BountyCardType
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import Badge from "src/Components/Badge/Badge"
|
||||
import { Link } from "react-router-dom"
|
||||
import { trimText } from "src/utils/helperFunctions"
|
||||
import VoteButton from "src/Components/VoteButton/VoteButton"
|
||||
import { Tag } from "src/graphql"
|
||||
|
||||
export type QuestionCardType = Pick<Question,
|
||||
| 'id'
|
||||
@@ -15,7 +16,6 @@ export type QuestionCardType = Pick<Question,
|
||||
| 'author'
|
||||
| 'excerpt'
|
||||
| 'votes_count'
|
||||
| "tags"
|
||||
| "answers_count"
|
||||
> & {
|
||||
comments: Array<Pick<Question['comments'][number],
|
||||
@@ -24,6 +24,7 @@ export type QuestionCardType = Pick<Question,
|
||||
| 'body'
|
||||
| 'createdAt'
|
||||
>>
|
||||
tags: Array<Pick<Tag, 'id' | "title">>
|
||||
};
|
||||
interface Props {
|
||||
question: QuestionCardType
|
||||
|
||||
@@ -4,7 +4,8 @@ import { BiComment } from 'react-icons/bi'
|
||||
import { Link } from "react-router-dom"
|
||||
import VoteButton from "src/Components/VoteButton/VoteButton"
|
||||
import { useVote } from "src/utils/hooks"
|
||||
import { Vote_Item_Type } from 'src/graphql';
|
||||
import { Tag, Vote_Item_Type } from 'src/graphql';
|
||||
import Badge from "src/Components/Badge/Badge"
|
||||
|
||||
export type StoryCardType = Pick<Story,
|
||||
| 'id'
|
||||
@@ -16,7 +17,9 @@ export type StoryCardType = Pick<Story,
|
||||
| 'excerpt'
|
||||
| 'votes_count'
|
||||
| 'comments_count'
|
||||
>;
|
||||
> & {
|
||||
tags: Array<Pick<Tag, 'id' | "title">>
|
||||
};
|
||||
|
||||
interface Props {
|
||||
story: StoryCardType
|
||||
@@ -37,6 +40,11 @@ export default function StoryCard({ story }: Props) {
|
||||
<h2 className="text-h5 font-bolder mt-16">{story.title}</h2>
|
||||
</Link>
|
||||
<p className="text-body4 text-gray-600 mt-8">{story.excerpt}...</p>
|
||||
<div className="flex gap-8 mt-8">
|
||||
{story.tags.map(tag => <Badge key={tag.id} size='sm'>
|
||||
{tag.title}
|
||||
</Badge>)}
|
||||
</div>
|
||||
|
||||
<hr className="my-16 bg-gray-200" />
|
||||
<div className="flex gap-24 items-center">
|
||||
|
||||
@@ -6,9 +6,8 @@ import FilesInput from "src/Components/Inputs/FilesInput/FilesInput";
|
||||
import TagsInput from "src/Components/Inputs/TagsInput/TagsInput";
|
||||
import * as yup from "yup";
|
||||
import ContentEditor from "../ContentEditor/ContentEditor";
|
||||
import { Topic, useCreateStoryMutation } from 'src/graphql'
|
||||
import { useCreateStoryMutation } from 'src/graphql'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import TopicsInput from '../TopicsInput/TopicsInput'
|
||||
import { useAppDispatch, useAppSelector } from 'src/utils/hooks';
|
||||
import { stageStory } from 'src/redux/features/staging.slice'
|
||||
import { Override } from 'src/utils/interfaces';
|
||||
@@ -32,7 +31,6 @@ const FileSchema = yup.lazy((value: string | File[]) => {
|
||||
|
||||
const schema = yup.object({
|
||||
title: yup.string().required().min(10),
|
||||
topic: yup.object().nullable().required(),
|
||||
tags: yup.array().required().min(1),
|
||||
body: yup.string().required().min(50, 'you have to write at least 10 words'),
|
||||
cover_image: yup.array().of(FileSchema as any)
|
||||
@@ -43,7 +41,6 @@ const schema = yup.object({
|
||||
interface IFormInputs {
|
||||
id: number | null
|
||||
title: string
|
||||
topic: NestedValue<Topic> | null
|
||||
tags: NestedValue<{ title: string }[]>
|
||||
cover_image: NestedValue<File[]> | NestedValue<string[]>
|
||||
body: string
|
||||
@@ -52,7 +49,6 @@ interface IFormInputs {
|
||||
|
||||
|
||||
export type CreateStoryType = Override<IFormInputs, {
|
||||
topic: Topic | null
|
||||
tags: { title: string }[]
|
||||
cover_image: File[] | string[]
|
||||
}>
|
||||
@@ -70,7 +66,6 @@ export default function StoryForm() {
|
||||
defaultValues: {
|
||||
id: story?.id ?? null,
|
||||
title: story?.title ?? '',
|
||||
topic: story?.topic ?? null,
|
||||
cover_image: story?.cover_image ?? [],
|
||||
tags: story?.tags ?? [],
|
||||
body: story?.body ?? '',
|
||||
@@ -113,7 +108,6 @@ export default function StoryForm() {
|
||||
body: data.body,
|
||||
tags: data.tags.map(t => t.title),
|
||||
cover_image: data.cover_image[0] as string,
|
||||
topicId: 1,
|
||||
},
|
||||
}
|
||||
})
|
||||
@@ -160,30 +154,11 @@ export default function StoryForm() {
|
||||
{errors.title.message}
|
||||
</p>}
|
||||
|
||||
<p className="text-body5 mt-16">
|
||||
Topic
|
||||
</p>
|
||||
<div className="mt-16">
|
||||
<Controller
|
||||
control={control}
|
||||
name="topic"
|
||||
render={({ field: { onChange, value, onBlur } }) => (
|
||||
<TopicsInput
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{errors.topic && <p className="input-error">
|
||||
{errors.topic.message}
|
||||
</p>}
|
||||
<p className="text-body5 mt-16">
|
||||
Tags
|
||||
</p>
|
||||
<TagsInput
|
||||
placeholder="Enter your tag and click enter. You can add multiple tags to your post"
|
||||
placeholder="Search from popular tags or add your own by clicking Enter."
|
||||
classes={{ container: 'mt-8' }}
|
||||
/>
|
||||
{errors.tags && <p className="input-error">
|
||||
|
||||
@@ -8,11 +8,6 @@ mutation createStory($data: StoryInputType) {
|
||||
id
|
||||
title
|
||||
}
|
||||
topic {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
votes_count
|
||||
type
|
||||
cover_image
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import React from 'react'
|
||||
import AutoComplete from 'src/Components/Inputs/Autocomplete/Autocomplete'
|
||||
import { Topic, useAllTopicsQuery } from 'src/graphql'
|
||||
import { ControlledStateHandler } from 'src/utils/interfaces';
|
||||
|
||||
|
||||
|
||||
type Props<IsMulti extends boolean> = ControlledStateHandler<Topic, IsMulti>
|
||||
|
||||
|
||||
|
||||
export default function TopicsInput<IsMulti extends boolean = false>(props: Props<IsMulti>) {
|
||||
|
||||
const topicsQuery = useAllTopicsQuery();
|
||||
|
||||
return (
|
||||
<AutoComplete
|
||||
isClearable
|
||||
placeholder='Choose a topic'
|
||||
options={topicsQuery.data?.allTopics!}
|
||||
labelField='title'
|
||||
valueField='id'
|
||||
isMulti={props.isMulti}
|
||||
isLoading={topicsQuery.loading}
|
||||
value={props.value}
|
||||
onChange={props.onChange}
|
||||
onBlur={props.onBlur}
|
||||
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -5,18 +5,19 @@ import { useFeedQuery } from 'src/graphql'
|
||||
import { useAppSelector, useInfiniteQuery } from 'src/utils/hooks'
|
||||
import PostsList from '../../Components/PostsList/PostsList'
|
||||
import TrendingCard from '../../Components/TrendingCard/TrendingCard'
|
||||
import PopularTopicsFilter from './PopularTopicsFilter/PopularTopicsFilter'
|
||||
import PopularTagsFilter, { FilterTag } from './PopularTagsFilter/PopularTagsFilter'
|
||||
import SortBy from './SortBy/SortBy'
|
||||
import styles from './styles.module.scss'
|
||||
import { Helmet } from "react-helmet";
|
||||
import Button from 'src/Components/Button/Button'
|
||||
import { FaDiscord } from 'react-icons/fa'
|
||||
import { FiArrowRight } from 'react-icons/fi'
|
||||
|
||||
|
||||
export default function FeedPage() {
|
||||
|
||||
const [sortByFilter, setSortByFilter] = useState<string | null>(null)
|
||||
const [topicFilter, setTopicFilter] = useState<number | null>(null)
|
||||
const [tagFilter, setTagFilter] = useState<FilterTag | null>(null)
|
||||
|
||||
|
||||
const feedQuery = useFeedQuery({
|
||||
@@ -24,11 +25,11 @@ export default function FeedPage() {
|
||||
take: 10,
|
||||
skip: 0,
|
||||
sortBy: sortByFilter,
|
||||
topic: topicFilter
|
||||
tag: tagFilter?.id ?? null
|
||||
},
|
||||
})
|
||||
const { fetchMore, isFetchingMore, variablesChanged } = useInfiniteQuery(feedQuery, 'getFeed')
|
||||
useUpdateEffect(variablesChanged, [sortByFilter, topicFilter]);
|
||||
useUpdateEffect(variablesChanged, [sortByFilter, tagFilter]);
|
||||
|
||||
const { navHeight, isLoggedIn } = useAppSelector((state) => ({
|
||||
navHeight: state.ui.navHeight,
|
||||
@@ -45,7 +46,19 @@ export default function FeedPage() {
|
||||
<div
|
||||
className={`page-container pt-16 w-full ${styles.grid}`}
|
||||
>
|
||||
<h1 id='title' className="text-h2 font-bolder">Stories ✍🏼</h1>
|
||||
<div id="title">
|
||||
{tagFilter && <p className="text-body6 text-gray-500 font-medium mb-8">
|
||||
<span className='cursor-pointer' onClick={() => setTagFilter(null)}>Stories </span>
|
||||
<FiArrowRight />
|
||||
<span> {tagFilter.title}</span>
|
||||
</p>}
|
||||
<h1 className="text-h2 font-bolder">{
|
||||
tagFilter ?
|
||||
<>{tagFilter.icon} {tagFilter.title}</>
|
||||
:
|
||||
"Stories ✍🏼"
|
||||
}</h1>
|
||||
</div>
|
||||
<div id="sort-by">
|
||||
<SortBy
|
||||
filterChanged={setSortByFilter}
|
||||
@@ -71,12 +84,13 @@ export default function FeedPage() {
|
||||
color='primary'
|
||||
fullWidth
|
||||
>
|
||||
Create a story
|
||||
Write a story
|
||||
</Button>}
|
||||
<div className="my-24"></div>
|
||||
<div className="my-24"></div>
|
||||
<PopularTopicsFilter
|
||||
filterChanged={setTopicFilter}
|
||||
<PopularTagsFilter
|
||||
value={tagFilter}
|
||||
onChange={setTagFilter as any}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import PopularTags from './PopularTagsFilter';
|
||||
|
||||
export default {
|
||||
title: 'Posts/Feed Page/Components/Popular Topics Filter',
|
||||
component: PopularTags,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
} as ComponentMeta<typeof PopularTags>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof PopularTags> = (args) => <div className="max-w-[326px]"><PopularTags {...args as any} ></PopularTags></div>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,39 @@
|
||||
import { useMediaQuery } from 'src/utils/hooks';
|
||||
import React, { useState } from 'react'
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import Slider from 'src/Components/Slider/Slider';
|
||||
import { usePopularTopicsQuery } from 'src/graphql';
|
||||
import { Tag, usePopularTagsQuery } from 'src/graphql';
|
||||
import { MEDIA_QUERIES } from 'src/utils/theme';
|
||||
|
||||
export type FilterTag = Pick<Tag, 'id' | 'title' | "icon">
|
||||
|
||||
interface Props {
|
||||
filterChanged?: (newFilter: number | null) => void
|
||||
value: FilterTag | null,
|
||||
onChange?: (newFilter: FilterTag | null) => void
|
||||
}
|
||||
|
||||
export default function PopularTopicsFilter({ filterChanged }: Props) {
|
||||
|
||||
const [selected, setSelected] = useState<number | null>(null);
|
||||
|
||||
const topicsQuery = usePopularTopicsQuery();
|
||||
export default function PopularTagsFilter({ value, onChange }: Props) {
|
||||
|
||||
|
||||
const filterClicked = (_newValue: number) => {
|
||||
const newValue = selected !== _newValue ? _newValue : null;
|
||||
setSelected(newValue);
|
||||
filterChanged?.(newValue);
|
||||
const tagsQuery = usePopularTagsQuery();
|
||||
|
||||
|
||||
const filterClicked = (_newValue: FilterTag) => {
|
||||
const newValue = value?.id === _newValue.id ? null : _newValue
|
||||
onChange?.(newValue);
|
||||
}
|
||||
|
||||
const selectedId = value?.id
|
||||
|
||||
const isMdScreen = useMediaQuery(MEDIA_QUERIES.isMedium)
|
||||
|
||||
return (
|
||||
<div className='overflow-hidden'>
|
||||
{isMdScreen ?
|
||||
<div className='bg-white border-2 border-gray-200 rounded-12 p-16'>
|
||||
<p className="text-body2 font-bolder text-black mb-16">Explore Categories</p>
|
||||
<p className="text-body2 font-bolder text-black mb-16">Popular Tags</p>
|
||||
<ul className=' flex flex-col gap-16'>
|
||||
{topicsQuery.loading ?
|
||||
Array(3).fill(0).map((_, idx) => <li
|
||||
{tagsQuery.loading ?
|
||||
Array(5).fill(0).map((_, idx) => <li
|
||||
key={idx}
|
||||
className={`flex items-start rounded-8 font-bold`}
|
||||
|
||||
@@ -43,18 +44,18 @@ export default function PopularTopicsFilter({ filterChanged }: Props) {
|
||||
</li>
|
||||
)
|
||||
:
|
||||
topicsQuery.data?.popularTopics.map((topic, idx) => <li
|
||||
key={topic.id}
|
||||
tagsQuery.data?.popularTags.map((tag) => <li
|
||||
key={tag.id}
|
||||
className={`flex items-start rounded-8 cursor-pointer font-bold
|
||||
active:scale-95 transition-transform
|
||||
${topic.id === selected ? 'bg-gray-200' : 'hover:bg-gray-100'}
|
||||
${tag.id === selectedId ? 'bg-gray-200' : 'hover:bg-gray-100'}
|
||||
`}
|
||||
role='button'
|
||||
onClick={() => filterClicked(topic.id)}
|
||||
onClick={() => filterClicked(tag)}
|
||||
>
|
||||
<span className={`${topic.id !== selected && 'bg-gray-50'} rounded-8 w-40 h-40 text-center py-8`}>{topic.icon}</span>
|
||||
<span className={`${tag.id !== selectedId && 'bg-gray-50'} rounded-8 w-40 h-40 text-center py-8`}>{tag.icon}</span>
|
||||
<span className="self-center px-16">
|
||||
{topic.title}
|
||||
{tag.title}
|
||||
</span>
|
||||
</li>)}
|
||||
</ul>
|
||||
@@ -62,18 +63,18 @@ export default function PopularTopicsFilter({ filterChanged }: Props) {
|
||||
:
|
||||
<>
|
||||
{
|
||||
topicsQuery.loading ?
|
||||
tagsQuery.loading ?
|
||||
<ul className="flex gap-8 ">
|
||||
{Array(4).fill(0).map((_, idx) => <div key={idx} className="py-12 px-16 bg-gray-100 rounded-8 text-body5"><span className="opacity-0">Category</span></div>)}
|
||||
</ul>
|
||||
:
|
||||
<Slider>
|
||||
{topicsQuery.data?.popularTopics.map(topic =>
|
||||
{tagsQuery.data?.popularTags.map(tag =>
|
||||
<div
|
||||
key={topic.id}
|
||||
onClick={() => filterClicked(topic.id)}
|
||||
className={`${topic.id === selected ? 'bg-gray-200' : "bg-gray-100"} py-12 px-16 rounded-8 text-body5`}
|
||||
>{topic.icon} {topic.title}</div>)}
|
||||
key={tag.id}
|
||||
onClick={() => filterClicked(tag)}
|
||||
className={`${tag.id === selectedId ? 'bg-gray-200' : "bg-gray-100"} py-12 px-16 rounded-8 text-body5`}
|
||||
>{tag.icon} {tag.title}</div>)}
|
||||
</Slider>
|
||||
}
|
||||
</>
|
||||
@@ -0,0 +1,7 @@
|
||||
query PopularTags {
|
||||
popularTags {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import PopularTopicsFilter from './PopularTopicsFilter';
|
||||
|
||||
export default {
|
||||
title: 'Posts/Feed Page/Components/Popular Topics Filter',
|
||||
component: PopularTopicsFilter,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
} as ComponentMeta<typeof PopularTopicsFilter>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof PopularTopicsFilter> = (args) => <div className="max-w-[326px]"><PopularTopicsFilter {...args as any} ></PopularTopicsFilter></div>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
query PopularTopics {
|
||||
popularTopics {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
query Feed($take: Int, $skip: Int, $sortBy: String, $topic: Int) {
|
||||
getFeed(take: $take, skip: $skip, sortBy: $sortBy, topic: $topic) {
|
||||
query Feed($take: Int, $skip: Int, $sortBy: String, $tag: Int) {
|
||||
getFeed(take: $take, skip: $skip, sortBy: $sortBy, tag: $tag) {
|
||||
... on Story {
|
||||
id
|
||||
title
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-template-rows: auto auto 1fr;
|
||||
|
||||
grid-template-areas:
|
||||
"categories title title side"
|
||||
|
||||
@@ -3,14 +3,11 @@ import { Story } from "src/features/Posts/types"
|
||||
import { marked } from 'marked';
|
||||
import styles from '../PageContent/styles.module.css'
|
||||
import Badge from "src/Components/Badge/Badge";
|
||||
import { BiComment } from "react-icons/bi";
|
||||
import { RiFlashlightLine } from "react-icons/ri";
|
||||
import { numberFormatter } from "src/utils/helperFunctions";
|
||||
import IconButton from "src/Components/IconButton/IconButton";
|
||||
import { BsThreeDotsVertical } from "react-icons/bs";
|
||||
import { Menu, MenuButton, MenuItem } from "@szhsin/react-menu";
|
||||
import { Menu, MenuItem } from "@szhsin/react-menu";
|
||||
import { useAppSelector } from "src/utils/hooks";
|
||||
import { useUpdateStory } from './useUpdateStory'
|
||||
import { FaPen } from "react-icons/fa";
|
||||
|
||||
|
||||
interface Props {
|
||||
@@ -29,28 +26,29 @@ export default function StoryPageContent({ story }: Props) {
|
||||
return (
|
||||
<>
|
||||
<div id="content" className="bg-white p-32 border-2 border-gray-200 rounded-16 relative">
|
||||
{curUser?.id === story.author.id && <Menu
|
||||
menuClassName='!p-8 !rounded-12'
|
||||
menuButton={<IconButton className="absolute top-32 right-32"><BsThreeDotsVertical /></IconButton>}>
|
||||
<MenuItem
|
||||
onClick={handleEdit}
|
||||
className='!p-16 font-medium flex gap-16 hover:bg-gray-100 !rounded-12'
|
||||
>
|
||||
Edit story
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={handleDelete}
|
||||
className='!p-16 font-medium flex gap-16 hover:bg-gray-100 !rounded-12'
|
||||
>
|
||||
Delete
|
||||
</MenuItem>
|
||||
</Menu>}
|
||||
|
||||
|
||||
{story.cover_image &&
|
||||
<img src={story.cover_image}
|
||||
className='w-full h-[120px] md:h-[240px] object-cover rounded-12 mb-16'
|
||||
alt="" />}
|
||||
<div className="flex flex-col gap-24">
|
||||
<div className="flex flex-col gap-24 relative">
|
||||
{curUser?.id === story.author.id && <Menu
|
||||
menuClassName='!p-8 !rounded-12'
|
||||
menuButton={<IconButton className="absolute top-0 right-0 text-gray-400"><FaPen /></IconButton>}>
|
||||
<MenuItem
|
||||
onClick={handleEdit}
|
||||
className='!p-16 font-medium flex gap-16 hover:bg-gray-100 !rounded-12'
|
||||
>
|
||||
Edit story
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={handleDelete}
|
||||
className='!p-16 font-medium flex gap-16 hover:bg-gray-100 !rounded-12'
|
||||
>
|
||||
Delete
|
||||
</MenuItem>
|
||||
</Menu>}
|
||||
<h1 className="text-h2 font-bolder">{story.title}</h1>
|
||||
<Header size="lg" showTimeAgo={false} author={story.author} date={story.createdAt} />
|
||||
{story.tags.length > 0 && <div className="flex gap-8">
|
||||
|
||||
@@ -15,11 +15,6 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
|
||||
id
|
||||
title
|
||||
}
|
||||
topic {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
votes_count
|
||||
type
|
||||
cover_image
|
||||
|
||||
@@ -13,13 +13,28 @@ interface Props {
|
||||
| 'author'
|
||||
> & {
|
||||
tags: Array<{ title: string }>
|
||||
cover_image?: string | File
|
||||
}
|
||||
}
|
||||
|
||||
export default function PreviewPostContent({ post }: Props) {
|
||||
|
||||
let coverImg: string;
|
||||
if (!post.cover_image)
|
||||
coverImg = "";
|
||||
else if (typeof post.cover_image === 'string')
|
||||
coverImg = post.cover_image;
|
||||
else
|
||||
coverImg = URL.createObjectURL(post.cover_image);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="content" className="bg-white p-32 border rounded-16">
|
||||
{coverImg &&
|
||||
<img src={coverImg}
|
||||
className='w-full h-[120px] md:h-[240px] object-cover rounded-12 mb-16'
|
||||
alt="" />}
|
||||
<div className="flex flex-col gap-24">
|
||||
<Header size="lg" showTimeAgo={false} author={post.author} date={post.createdAt} />
|
||||
<h1 className="text-h2 font-bolder">{post.title}</h1>
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function PreviewPostPage() {
|
||||
/>
|
||||
</div>
|
||||
</aside>
|
||||
<PreviewPostContent post={{ ...post, createdAt: new Date().toISOString(), author: author! }} />
|
||||
<PreviewPostContent post={{ ...post, createdAt: new Date().toISOString(), author: author!, cover_image: post.cover_image[0] }} />
|
||||
<aside id='author' className='no-scrollbar min-w-0'>
|
||||
<div className="flex flex-col gap-24"
|
||||
style={{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useQuery } from '@apollo/client';
|
||||
import Badge from 'src/Components/Badge/Badge'
|
||||
|
||||
import Slider from 'src/Components/Slider/Slider'
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAllCategoriesQuery } from 'src/graphql';
|
||||
|
||||
const colors = [
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
import { ComponentProps } from "react";
|
||||
|
||||
import { lazyModal } from "src/utils/helperFunctions";
|
||||
import { Id } from "src/utils/types/utils";
|
||||
|
||||
const x = () => import('./Claim_CopySignatureCard');
|
||||
|
||||
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T
|
||||
type y = Id<ThenArg<ReturnType<typeof x>>>
|
||||
// type yy = ComponentProps<y['default']>
|
||||
export const { LazyComponent: Claim_CopySignatureCard } = lazyModal(() => import('./Claim_CopySignatureCard'))
|
||||
export const { LazyComponent: Claim_FundWithdrawCard } = lazyModal(() => import('./Claim_FundWithdrawCard'))
|
||||
export const { LazyComponent: Claim_GenerateSignatureCard } = lazyModal(() => import('./Claim_GenerateSignatureCard'))
|
||||
|
||||
@@ -98,8 +98,8 @@ export type Hackathon = {
|
||||
id: Scalars['Int'];
|
||||
location: Scalars['String'];
|
||||
start_date: Scalars['Date'];
|
||||
tags: Array<Tag>;
|
||||
title: Scalars['String'];
|
||||
topics: Array<Topic>;
|
||||
website: Scalars['String'];
|
||||
};
|
||||
|
||||
@@ -209,7 +209,6 @@ export type Query = {
|
||||
__typename?: 'Query';
|
||||
allCategories: Array<Category>;
|
||||
allProjects: Array<Project>;
|
||||
allTopics: Array<Topic>;
|
||||
getAllHackathons: Array<Hackathon>;
|
||||
getCategory: Category;
|
||||
getDonationsStats: DonationsStats;
|
||||
@@ -221,7 +220,8 @@ export type Query = {
|
||||
hottestProjects: Array<Project>;
|
||||
me: Maybe<User>;
|
||||
newProjects: Array<Project>;
|
||||
popularTopics: Array<Topic>;
|
||||
officialTags: Array<Tag>;
|
||||
popularTags: Array<Tag>;
|
||||
profile: Maybe<User>;
|
||||
projectsByCategory: Array<Project>;
|
||||
searchProjects: Array<Project>;
|
||||
@@ -236,7 +236,7 @@ export type QueryAllProjectsArgs = {
|
||||
|
||||
export type QueryGetAllHackathonsArgs = {
|
||||
sortBy: InputMaybe<Scalars['String']>;
|
||||
topic: InputMaybe<Scalars['Int']>;
|
||||
tag: InputMaybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
|
||||
@@ -247,9 +247,9 @@ export type QueryGetCategoryArgs = {
|
||||
|
||||
export type QueryGetFeedArgs = {
|
||||
skip?: InputMaybe<Scalars['Int']>;
|
||||
sortBy?: InputMaybe<Scalars['String']>;
|
||||
sortBy: InputMaybe<Scalars['String']>;
|
||||
tag?: InputMaybe<Scalars['Int']>;
|
||||
take?: InputMaybe<Scalars['Int']>;
|
||||
topic?: InputMaybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
|
||||
@@ -326,7 +326,6 @@ export type Story = PostBase & {
|
||||
id: Scalars['Int'];
|
||||
tags: Array<Tag>;
|
||||
title: Scalars['String'];
|
||||
topic: Topic;
|
||||
type: Scalars['String'];
|
||||
votes_count: Scalars['Int'];
|
||||
};
|
||||
@@ -337,19 +336,13 @@ export type StoryInputType = {
|
||||
id: InputMaybe<Scalars['Int']>;
|
||||
tags: Array<Scalars['String']>;
|
||||
title: Scalars['String'];
|
||||
topicId: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type Tag = {
|
||||
__typename?: 'Tag';
|
||||
icon: Maybe<Scalars['String']>;
|
||||
id: Scalars['Int'];
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
export type Topic = {
|
||||
__typename?: 'Topic';
|
||||
icon: Scalars['String'];
|
||||
id: Scalars['Int'];
|
||||
isOfficial: Maybe<Scalars['Boolean']>;
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
@@ -405,6 +398,11 @@ export type Vote = {
|
||||
payment_request: Scalars['String'];
|
||||
};
|
||||
|
||||
export type OfficialTagsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type OfficialTagsQuery = { __typename?: 'Query', officialTags: Array<{ __typename?: 'Tag', id: number, title: string, icon: string | null }> };
|
||||
|
||||
export type NavCategoriesQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
@@ -442,18 +440,13 @@ export type ConfirmDonationMutationVariables = Exact<{
|
||||
|
||||
export type ConfirmDonationMutation = { __typename?: 'Mutation', confirmDonation: { __typename?: 'Donation', id: number, amount: number, paid: boolean } };
|
||||
|
||||
export type AllTopicsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type AllTopicsQuery = { __typename?: 'Query', allTopics: Array<{ __typename?: 'Topic', id: number, title: string, icon: string }> };
|
||||
|
||||
export type GetHackathonsQueryVariables = Exact<{
|
||||
sortBy: InputMaybe<Scalars['String']>;
|
||||
topic: InputMaybe<Scalars['Int']>;
|
||||
tag: InputMaybe<Scalars['Int']>;
|
||||
}>;
|
||||
|
||||
|
||||
export type GetHackathonsQuery = { __typename?: 'Query', getAllHackathons: Array<{ __typename?: 'Hackathon', id: number, title: string, description: string, cover_image: string, start_date: any, end_date: any, location: string, website: string, topics: Array<{ __typename?: 'Topic', id: number, title: string, icon: string }> }> };
|
||||
export type GetHackathonsQuery = { __typename?: 'Query', getAllHackathons: Array<{ __typename?: 'Hackathon', id: number, title: string, description: string, cover_image: string, start_date: any, end_date: any, location: string, website: string, tags: Array<{ __typename?: 'Tag', id: number, title: string, icon: string | null }> }> };
|
||||
|
||||
export type TrendingPostsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -465,7 +458,7 @@ export type CreateStoryMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateStoryMutation = { __typename?: 'Mutation', createStory: { __typename?: 'Story', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string, comments_count: number, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, topic: { __typename?: 'Topic', id: number, title: string, icon: string } } | null };
|
||||
export type CreateStoryMutation = { __typename?: 'Mutation', createStory: { __typename?: 'Story', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string, comments_count: number, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | null };
|
||||
|
||||
export type DeleteStoryMutationVariables = Exact<{
|
||||
deleteStoryId: Scalars['Int'];
|
||||
@@ -474,16 +467,16 @@ export type DeleteStoryMutationVariables = Exact<{
|
||||
|
||||
export type DeleteStoryMutation = { __typename?: 'Mutation', deleteStory: { __typename?: 'Story', id: number } | null };
|
||||
|
||||
export type PopularTopicsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
export type PopularTagsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type PopularTopicsQuery = { __typename?: 'Query', popularTopics: Array<{ __typename?: 'Topic', id: number, title: string, icon: string }> };
|
||||
export type PopularTagsQuery = { __typename?: 'Query', popularTags: Array<{ __typename?: 'Tag', id: number, title: string, icon: string | null }> };
|
||||
|
||||
export type FeedQueryVariables = Exact<{
|
||||
take: InputMaybe<Scalars['Int']>;
|
||||
skip: InputMaybe<Scalars['Int']>;
|
||||
sortBy: InputMaybe<Scalars['String']>;
|
||||
topic: InputMaybe<Scalars['Int']>;
|
||||
tag: InputMaybe<Scalars['Int']>;
|
||||
}>;
|
||||
|
||||
|
||||
@@ -495,7 +488,7 @@ 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, 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, answers_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, createdAt: any, body: string, votes_count: number, parentId: number | null, author: { __typename?: 'Author', id: number, name: string, avatar: string } }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, topic: { __typename?: 'Topic', id: number, title: string, icon: string }, comments: Array<{ __typename?: 'PostComment', id: number, createdAt: any, body: string, votes_count: number, parentId: number | null, author: { __typename?: 'Author', id: number, name: string, avatar: string } }> } };
|
||||
export type PostDetailsQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string, 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, answers_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, createdAt: any, body: string, votes_count: number, parentId: number | null, author: { __typename?: 'Author', id: number, name: string, avatar: string } }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, createdAt: any, body: string, votes_count: number, parentId: number | null, author: { __typename?: 'Author', id: number, name: string, avatar: string } }> } };
|
||||
|
||||
export type ProfileQueryVariables = Exact<{
|
||||
profileId: Scalars['Int'];
|
||||
@@ -558,6 +551,42 @@ 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 OfficialTagsDocument = gql`
|
||||
query OfficialTags {
|
||||
officialTags {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useOfficialTagsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useOfficialTagsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useOfficialTagsQuery` 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 } = useOfficialTagsQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useOfficialTagsQuery(baseOptions?: Apollo.QueryHookOptions<OfficialTagsQuery, OfficialTagsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<OfficialTagsQuery, OfficialTagsQueryVariables>(OfficialTagsDocument, options);
|
||||
}
|
||||
export function useOfficialTagsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<OfficialTagsQuery, OfficialTagsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<OfficialTagsQuery, OfficialTagsQueryVariables>(OfficialTagsDocument, options);
|
||||
}
|
||||
export type OfficialTagsQueryHookResult = ReturnType<typeof useOfficialTagsQuery>;
|
||||
export type OfficialTagsLazyQueryHookResult = ReturnType<typeof useOfficialTagsLazyQuery>;
|
||||
export type OfficialTagsQueryResult = Apollo.QueryResult<OfficialTagsQuery, OfficialTagsQueryVariables>;
|
||||
export const NavCategoriesDocument = gql`
|
||||
query NavCategories {
|
||||
allCategories {
|
||||
@@ -782,45 +811,9 @@ export function useConfirmDonationMutation(baseOptions?: Apollo.MutationHookOpti
|
||||
export type ConfirmDonationMutationHookResult = ReturnType<typeof useConfirmDonationMutation>;
|
||||
export type ConfirmDonationMutationResult = Apollo.MutationResult<ConfirmDonationMutation>;
|
||||
export type ConfirmDonationMutationOptions = Apollo.BaseMutationOptions<ConfirmDonationMutation, ConfirmDonationMutationVariables>;
|
||||
export const AllTopicsDocument = gql`
|
||||
query allTopics {
|
||||
allTopics {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useAllTopicsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useAllTopicsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useAllTopicsQuery` 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 } = useAllTopicsQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useAllTopicsQuery(baseOptions?: Apollo.QueryHookOptions<AllTopicsQuery, AllTopicsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<AllTopicsQuery, AllTopicsQueryVariables>(AllTopicsDocument, options);
|
||||
}
|
||||
export function useAllTopicsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AllTopicsQuery, AllTopicsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<AllTopicsQuery, AllTopicsQueryVariables>(AllTopicsDocument, options);
|
||||
}
|
||||
export type AllTopicsQueryHookResult = ReturnType<typeof useAllTopicsQuery>;
|
||||
export type AllTopicsLazyQueryHookResult = ReturnType<typeof useAllTopicsLazyQuery>;
|
||||
export type AllTopicsQueryResult = Apollo.QueryResult<AllTopicsQuery, AllTopicsQueryVariables>;
|
||||
export const GetHackathonsDocument = gql`
|
||||
query getHackathons($sortBy: String, $topic: Int) {
|
||||
getAllHackathons(sortBy: $sortBy, topic: $topic) {
|
||||
query getHackathons($sortBy: String, $tag: Int) {
|
||||
getAllHackathons(sortBy: $sortBy, tag: $tag) {
|
||||
id
|
||||
title
|
||||
description
|
||||
@@ -829,7 +822,7 @@ export const GetHackathonsDocument = gql`
|
||||
end_date
|
||||
location
|
||||
website
|
||||
topics {
|
||||
tags {
|
||||
id
|
||||
title
|
||||
icon
|
||||
@@ -851,7 +844,7 @@ export const GetHackathonsDocument = gql`
|
||||
* const { data, loading, error } = useGetHackathonsQuery({
|
||||
* variables: {
|
||||
* sortBy: // value for 'sortBy'
|
||||
* topic: // value for 'topic'
|
||||
* tag: // value for 'tag'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
@@ -934,11 +927,6 @@ export const CreateStoryDocument = gql`
|
||||
id
|
||||
title
|
||||
}
|
||||
topic {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
votes_count
|
||||
type
|
||||
cover_image
|
||||
@@ -1005,9 +993,9 @@ export function useDeleteStoryMutation(baseOptions?: Apollo.MutationHookOptions<
|
||||
export type DeleteStoryMutationHookResult = ReturnType<typeof useDeleteStoryMutation>;
|
||||
export type DeleteStoryMutationResult = Apollo.MutationResult<DeleteStoryMutation>;
|
||||
export type DeleteStoryMutationOptions = Apollo.BaseMutationOptions<DeleteStoryMutation, DeleteStoryMutationVariables>;
|
||||
export const PopularTopicsDocument = gql`
|
||||
query PopularTopics {
|
||||
popularTopics {
|
||||
export const PopularTagsDocument = gql`
|
||||
query PopularTags {
|
||||
popularTags {
|
||||
id
|
||||
title
|
||||
icon
|
||||
@@ -1016,34 +1004,34 @@ export const PopularTopicsDocument = gql`
|
||||
`;
|
||||
|
||||
/**
|
||||
* __usePopularTopicsQuery__
|
||||
* __usePopularTagsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `usePopularTopicsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `usePopularTopicsQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* To run a query within a React component, call `usePopularTagsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `usePopularTagsQuery` 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 } = usePopularTopicsQuery({
|
||||
* const { data, loading, error } = usePopularTagsQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function usePopularTopicsQuery(baseOptions?: Apollo.QueryHookOptions<PopularTopicsQuery, PopularTopicsQueryVariables>) {
|
||||
export function usePopularTagsQuery(baseOptions?: Apollo.QueryHookOptions<PopularTagsQuery, PopularTagsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<PopularTopicsQuery, PopularTopicsQueryVariables>(PopularTopicsDocument, options);
|
||||
return Apollo.useQuery<PopularTagsQuery, PopularTagsQueryVariables>(PopularTagsDocument, options);
|
||||
}
|
||||
export function usePopularTopicsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PopularTopicsQuery, PopularTopicsQueryVariables>) {
|
||||
export function usePopularTagsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PopularTagsQuery, PopularTagsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<PopularTopicsQuery, PopularTopicsQueryVariables>(PopularTopicsDocument, options);
|
||||
return Apollo.useLazyQuery<PopularTagsQuery, PopularTagsQueryVariables>(PopularTagsDocument, options);
|
||||
}
|
||||
export type PopularTopicsQueryHookResult = ReturnType<typeof usePopularTopicsQuery>;
|
||||
export type PopularTopicsLazyQueryHookResult = ReturnType<typeof usePopularTopicsLazyQuery>;
|
||||
export type PopularTopicsQueryResult = Apollo.QueryResult<PopularTopicsQuery, PopularTopicsQueryVariables>;
|
||||
export type PopularTagsQueryHookResult = ReturnType<typeof usePopularTagsQuery>;
|
||||
export type PopularTagsLazyQueryHookResult = ReturnType<typeof usePopularTagsLazyQuery>;
|
||||
export type PopularTagsQueryResult = Apollo.QueryResult<PopularTagsQuery, PopularTagsQueryVariables>;
|
||||
export const FeedDocument = gql`
|
||||
query Feed($take: Int, $skip: Int, $sortBy: String, $topic: Int) {
|
||||
getFeed(take: $take, skip: $skip, sortBy: $sortBy, topic: $topic) {
|
||||
query Feed($take: Int, $skip: Int, $sortBy: String, $tag: Int) {
|
||||
getFeed(take: $take, skip: $skip, sortBy: $sortBy, tag: $tag) {
|
||||
... on Story {
|
||||
id
|
||||
title
|
||||
@@ -1135,7 +1123,7 @@ export const FeedDocument = gql`
|
||||
* take: // value for 'take'
|
||||
* skip: // value for 'skip'
|
||||
* sortBy: // value for 'sortBy'
|
||||
* topic: // value for 'topic'
|
||||
* tag: // value for 'tag'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
@@ -1168,11 +1156,6 @@ export const PostDetailsDocument = gql`
|
||||
id
|
||||
title
|
||||
}
|
||||
topic {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
votes_count
|
||||
type
|
||||
cover_image
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Hackathon } from "src/graphql"
|
||||
import { topics } from "./topics"
|
||||
import { tags } from "./tags"
|
||||
import { getCoverImage, getItems } from "./utils"
|
||||
|
||||
|
||||
const generateTopics = () => getItems(topics, {
|
||||
const generateTags = () => getItems(tags, {
|
||||
min: 1,
|
||||
max: 4
|
||||
})
|
||||
@@ -18,7 +18,7 @@ export const hackathons = [
|
||||
location: "Instanbul, Turkey",
|
||||
cover_image: getCoverImage(),
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam quam felis ut interdum commodo, scelerisque.",
|
||||
topics: generateTopics(),
|
||||
tags: generateTags(),
|
||||
website: "https://bolt.fun/hackathons/shock-the-web"
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@ export const hackathons = [
|
||||
location: "Instanbul, Turkey",
|
||||
cover_image: getCoverImage(),
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam quam felis ut interdum commodo, scelerisque.",
|
||||
topics: generateTopics(),
|
||||
tags: generateTags(),
|
||||
website: "https://bolt.fun/hackathons/shock-the-web"
|
||||
},
|
||||
{
|
||||
@@ -40,7 +40,7 @@ export const hackathons = [
|
||||
location: "Instanbul, Turkey",
|
||||
cover_image: getCoverImage(),
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam quam felis ut interdum commodo, scelerisque.",
|
||||
topics: generateTopics(),
|
||||
tags: generateTags(),
|
||||
website: "https://bolt.fun/hackathons/shock-the-web"
|
||||
},
|
||||
{
|
||||
@@ -51,7 +51,7 @@ export const hackathons = [
|
||||
location: "Instanbul, Turkey",
|
||||
cover_image: getCoverImage(),
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam quam felis ut interdum commodo, scelerisque.",
|
||||
topics: generateTopics(),
|
||||
tags: generateTags(),
|
||||
website: "https://bolt.fun/hackathons/shock-the-web"
|
||||
},
|
||||
{
|
||||
@@ -62,7 +62,7 @@ export const hackathons = [
|
||||
location: "Instanbul, Turkey",
|
||||
cover_image: getCoverImage(),
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam quam felis ut interdum commodo, scelerisque.",
|
||||
topics: generateTopics(),
|
||||
tags: generateTags(),
|
||||
website: "https://bolt.fun/hackathons/shock-the-web"
|
||||
},
|
||||
{
|
||||
@@ -73,7 +73,7 @@ export const hackathons = [
|
||||
location: "Instanbul, Turkey",
|
||||
cover_image: getCoverImage(),
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam quam felis ut interdum commodo, scelerisque.",
|
||||
topics: generateTopics(),
|
||||
tags: generateTags(),
|
||||
website: "https://bolt.fun/hackathons/shock-the-web"
|
||||
},
|
||||
].map(i => ({ ...i, __typename: "Hackathon" })) as Hackathon[]
|
||||
@@ -1,10 +1,10 @@
|
||||
|
||||
import dayjs from "dayjs";
|
||||
import { Bounty, Post, Question, Story } from "src/features/Posts/types";
|
||||
import { random, randomItem } from "src/utils/helperFunctions";
|
||||
import { random, randomItem, randomItems } from "src/utils/helperFunctions";
|
||||
import { getAvatarImage, getCoverImage } from "./utils";
|
||||
import { Chance } from 'chance'
|
||||
import { topics } from "./topics";
|
||||
import { tags } from "./tags";
|
||||
|
||||
const getDate = () => dayjs().subtract(random(5, 48), 'hour').toString();
|
||||
|
||||
@@ -90,14 +90,9 @@ export let posts = {
|
||||
votes_count: 120,
|
||||
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
|
||||
type: "Story",
|
||||
tags: [
|
||||
{ id: 1, title: "lnurl" },
|
||||
{ id: 2, title: "webln" },
|
||||
{ id: 3, title: "guide" },
|
||||
],
|
||||
tags: randomItems(3, ...tags),
|
||||
author: getAuthor(),
|
||||
comments: generatePostComments(3),
|
||||
topic: randomItem(...topics)
|
||||
|
||||
},
|
||||
] as Story[],
|
||||
@@ -112,11 +107,7 @@ export let posts = {
|
||||
createdAt: getDate(),
|
||||
votes_count: 120,
|
||||
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
|
||||
tags: [
|
||||
{ id: 1, title: "lnurl" },
|
||||
{ id: 2, title: "webln" },
|
||||
{ id: 3, title: "guide" },
|
||||
],
|
||||
tags: randomItems(3, ...tags),
|
||||
author: getAuthor(),
|
||||
deadline: "25 May",
|
||||
reward_amount: 200_000,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Topic } from "src/graphql";
|
||||
import { Tag } from "src/graphql";
|
||||
|
||||
export const topics = [
|
||||
|
||||
export const tags = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Bitcoin',
|
||||
@@ -27,4 +28,4 @@ export const topics = [
|
||||
title: 'Design',
|
||||
icon: '🎨'
|
||||
}
|
||||
].map(i => ({ __typename: "Topic", ...i })) as Topic[]
|
||||
].map(i => ({ __typename: "Tag", ...i })) as Tag[]
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
import { graphql } from 'msw'
|
||||
import { allCategories, getAllHackathons, getCategory, getFeed, getPostById, getProject, getTrendingPosts, hottestProjects, me, newProjects, popularTopics, profile, projectsByCategory, searchProjects } from './resolvers'
|
||||
import { allCategories, getAllHackathons, getCategory, getFeed, getPostById, getProject, getTrendingPosts, hottestProjects, me, newProjects, popularTags, profile, projectsByCategory, searchProjects } from './resolvers'
|
||||
import {
|
||||
NavCategoriesQuery,
|
||||
ExploreProjectsQuery,
|
||||
@@ -19,12 +19,12 @@ import {
|
||||
PostDetailsQueryVariables,
|
||||
FeedQueryVariables,
|
||||
TrendingPostsQuery,
|
||||
PopularTopicsQuery,
|
||||
PopularTopicsQueryVariables,
|
||||
PopularTagsQuery,
|
||||
PopularTagsQueryVariables,
|
||||
GetHackathonsQuery,
|
||||
GetHackathonsQueryVariables,
|
||||
AllTopicsQuery,
|
||||
AllTopicsQueryVariables,
|
||||
OfficialTagsQuery,
|
||||
OfficialTagsQueryVariables,
|
||||
DonationsStatsQuery,
|
||||
MeQuery,
|
||||
ProfileQuery,
|
||||
@@ -111,20 +111,20 @@ export const handlers = [
|
||||
)
|
||||
}),
|
||||
|
||||
graphql.query<PopularTopicsQuery, PopularTopicsQueryVariables>('PopularTopics', async (req, res, ctx) => {
|
||||
graphql.query<PopularTagsQuery, PopularTagsQueryVariables>('PopularTags', async (req, res, ctx) => {
|
||||
await delay()
|
||||
return res(
|
||||
ctx.data({
|
||||
popularTopics: popularTopics()
|
||||
popularTags: popularTags()
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
graphql.query<AllTopicsQuery, AllTopicsQueryVariables>('allTopics', async (req, res, ctx) => {
|
||||
graphql.query<OfficialTagsQuery, OfficialTagsQueryVariables>('OfficialTags', async (req, res, ctx) => {
|
||||
await delay()
|
||||
return res(
|
||||
ctx.data({
|
||||
allTopics: popularTopics()
|
||||
officialTags: popularTags()
|
||||
})
|
||||
)
|
||||
}),
|
||||
@@ -135,7 +135,7 @@ export const handlers = [
|
||||
const { take, skip } = req.variables;
|
||||
return res(
|
||||
ctx.data({
|
||||
getFeed: getFeed({ take, skip, })
|
||||
getFeed: getFeed({ take, skip, sortBy: null, tag: null })
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MOCK_DATA } from "./data";
|
||||
import { Query, QueryGetFeedArgs, QueryGetPostByIdArgs } from 'src/graphql'
|
||||
import { Chance } from "chance";
|
||||
import { topics } from "./data/topics";
|
||||
import { tags } from "./data/tags";
|
||||
import { hackathons } from "./data/hackathon";
|
||||
import { shuffle } from "src/utils/helperFunctions";
|
||||
|
||||
@@ -63,8 +63,8 @@ export function getTrendingPosts(): Query['getTrendingPosts'] {
|
||||
return chance.pickset(MOCK_DATA.feed, 5);
|
||||
}
|
||||
|
||||
export function popularTopics() {
|
||||
return topics;
|
||||
export function popularTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
export function getAllHackathons() {
|
||||
|
||||
@@ -52,7 +52,7 @@ export const apolloClient = new ApolloClient({
|
||||
typePolicies: {
|
||||
Query: {
|
||||
fields: {
|
||||
getFeed: offsetLimitPagination(['sortBy', 'topic'])
|
||||
getFeed: offsetLimitPagination(['sortBy', 'tag'])
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { ComponentProps, ComponentType, ReactNode, Suspense } from "react";
|
||||
import React, { ComponentProps, ComponentType, Suspense } from "react";
|
||||
import { RotatingLines } from "react-loader-spinner";
|
||||
import { isNullOrUndefined } from "remirror";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useRef, useEffect, useCallback } from 'react'
|
||||
import { Action, AnyAction } from '@reduxjs/toolkit'
|
||||
import { Action } from '@reduxjs/toolkit'
|
||||
import { useStore } from 'react-redux'
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user