From 1a8b2eab05ea638d70d4f59e7863d37acd752ca6 Mon Sep 17 00:00:00 2001 From: "MTG\\mtg09" <50504183+MTG2000@users.noreply.github.com> Date: Mon, 18 Dec 2023 13:05:42 +0400 Subject: [PATCH] update (db): handle user relations in db in case of user deletion --- api/functions/graphql/nexus-typegen.ts | 10 +- api/functions/graphql/schema.graphql | 8 +- api/functions/graphql/types/post.js | 8 +- .../migration.sql | 83 +++++++++ prisma/schema.prisma | 38 ++-- .../PostCard/BountyCard/BountyCard.tsx | 163 +++++++++++------- .../PostCard/QuestionCard/QuestionCard.tsx | 117 +++++++------ .../PostCard/StoryCard/StoryCard.tsx | 16 +- .../Components/TrendingCard/TrendingCard.tsx | 87 ++++++---- .../AuthorCard/AuthorCard.stories.tsx | 29 ++-- .../AuthorCard/AuthorCard.stories.tsx | 29 ++-- .../BountyPageContent/BountyPageContent.tsx | 127 ++++++++------ .../QuestionPageContent.tsx | 14 +- .../StoryPageContent/StoryPageContent.tsx | 16 +- .../pages/PostDetailsPage/PostDetailsPage.tsx | 4 +- src/graphql/index.tsx | 16 +- 16 files changed, 468 insertions(+), 297 deletions(-) create mode 100644 prisma/migrations/20231218084605_set_delete_cascade_rules_for_user/migration.sql diff --git a/api/functions/graphql/nexus-typegen.ts b/api/functions/graphql/nexus-typegen.ts index 15aa565b..a1125cfe 100644 --- a/api/functions/graphql/nexus-typegen.ts +++ b/api/functions/graphql/nexus-typegen.ts @@ -393,7 +393,7 @@ export interface NexusGenObjects { projects: NexusGenRootTypes['ProjectInTournament'][]; // [ProjectInTournament!]! } PostComment: { // root type - author: NexusGenRootTypes['User']; // User! + author?: NexusGenRootTypes['User'] | null; // User body: string; // String! created_at: NexusGenScalars['Date']; // Date! id: number; // Int! @@ -653,7 +653,7 @@ export interface NexusGenFieldTypes { Bounty: { // field return type applicants_count: number; // Int! applications: NexusGenRootTypes['BountyApplication'][]; // [BountyApplication!]! - author: NexusGenRootTypes['User']; // User! + author: NexusGenRootTypes['User'] | null; // User body: string; // String! cover_image: string | null; // String createdAt: NexusGenScalars['Date']; // Date! @@ -784,7 +784,7 @@ export interface NexusGenFieldTypes { projects: NexusGenRootTypes['ProjectInTournament'][]; // [ProjectInTournament!]! } PostComment: { // field return type - author: NexusGenRootTypes['User']; // User! + author: NexusGenRootTypes['User'] | null; // User body: string; // String! created_at: NexusGenScalars['Date']; // Date! id: number; // Int! @@ -878,7 +878,7 @@ export interface NexusGenFieldTypes { usersByNostrKeys: NexusGenRootTypes['NostrKeyWithUser'][]; // [NostrKeyWithUser!]! } Question: { // field return type - author: NexusGenRootTypes['User']; // User! + author: NexusGenRootTypes['User'] | null; // User body: string; // String! createdAt: NexusGenScalars['Date']; // Date! excerpt: string; // String! @@ -892,7 +892,7 @@ export interface NexusGenFieldTypes { votes_count: number; // Int! } Story: { // field return type - author: NexusGenRootTypes['User']; // User! + author: NexusGenRootTypes['User'] | null; // User body: string; // String! comments: NexusGenRootTypes['PostComment'][]; // [PostComment!]! comments_count: number; // Int! diff --git a/api/functions/graphql/schema.graphql b/api/functions/graphql/schema.graphql index 11133552..da2b1cf4 100644 --- a/api/functions/graphql/schema.graphql +++ b/api/functions/graphql/schema.graphql @@ -54,7 +54,7 @@ interface BaseUser { type Bounty implements PostBase { applicants_count: Int! applications: [BountyApplication!]! - author: User! + author: User body: String! cover_image: String createdAt: Date! @@ -319,7 +319,7 @@ interface PostBase { } type PostComment { - author: User! + author: User body: String! created_at: Date! id: Int! @@ -451,7 +451,7 @@ type Query { } type Question implements PostBase { - author: User! + author: User body: String! createdAt: Date! excerpt: String! @@ -479,7 +479,7 @@ enum RoleLevelEnum { } type Story implements PostBase { - author: User! + author: User body: String! comments: [PostComment!]! comments_count: Int! diff --git a/api/functions/graphql/types/post.js b/api/functions/graphql/types/post.js index 66eb614e..77c01fb0 100644 --- a/api/functions/graphql/types/post.js +++ b/api/functions/graphql/types/post.js @@ -188,7 +188,7 @@ const Story = objectType({ return post._count.comments; }, }); - t.nonNull.field("author", { + t.field("author", { type: "User", resolve: (parent) => { return ( @@ -251,7 +251,7 @@ const Bounty = objectType({ t.nonNull.list.nonNull.field("applications", { type: "BountyApplication", }); - t.nonNull.field("author", { + t.field("author", { type: "User", resolve: (parent) => { return prisma.bounty.findUnique({ where: { id: parent.id } }).user(); @@ -287,7 +287,7 @@ const Question = objectType({ // } // }); - t.nonNull.field("author", { + t.field("author", { type: "User", resolve: (parent) => { return prisma.question.findUnique({ where: { id: parent.id } }).user(); @@ -302,7 +302,7 @@ const PostComment = objectType({ t.nonNull.int("id"); t.nonNull.date("created_at"); t.nonNull.string("body"); - t.nonNull.field("author", { + t.field("author", { type: "User", }); t.int("parentId"); diff --git a/prisma/migrations/20231218084605_set_delete_cascade_rules_for_user/migration.sql b/prisma/migrations/20231218084605_set_delete_cascade_rules_for_user/migration.sql new file mode 100644 index 00000000..af54b40f --- /dev/null +++ b/prisma/migrations/20231218084605_set_delete_cascade_rules_for_user/migration.sql @@ -0,0 +1,83 @@ +-- DropForeignKey +ALTER TABLE "FoundersClubMember" DROP CONSTRAINT "FoundersClubMember_user_id_fkey"; + +-- DropForeignKey +ALTER TABLE "NostrBadgeRequest" DROP CONSTRAINT "NostrBadgeRequest_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "ProjectMember" DROP CONSTRAINT "ProjectMember_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "TournamentJudgingRoundJudge" DROP CONSTRAINT "TournamentJudgingRoundJudge_judge_id_fkey"; + +-- DropForeignKey +ALTER TABLE "TournamentJudgingRoundJudgeScore" DROP CONSTRAINT "TournamentJudgingRoundJudgeScore_judge_id_fkey"; + +-- DropForeignKey +ALTER TABLE "TournamentOrganizer" DROP CONSTRAINT "TournamentOrganizer_user_id_fkey"; + +-- DropForeignKey +ALTER TABLE "TournamentParticipant" DROP CONSTRAINT "TournamentParticipant_user_id_fkey"; + +-- DropForeignKey +ALTER TABLE "UserAction" DROP CONSTRAINT "UserAction_user_id_fkey"; + +-- DropForeignKey +ALTER TABLE "UserBadge" DROP CONSTRAINT "UserBadge_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "UserBadgeProgress" DROP CONSTRAINT "UserBadgeProgress_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "UserEmail" DROP CONSTRAINT "UserEmail_user_id_fkey"; + +-- DropForeignKey +ALTER TABLE "UserKey" DROP CONSTRAINT "UserKey_user_id_fkey"; + +-- DropForeignKey +ALTER TABLE "UserNostrKey" DROP CONSTRAINT "UserNostrKey_user_id_fkey"; + +-- DropForeignKey +ALTER TABLE "UsersOnWorkRoles" DROP CONSTRAINT "UsersOnWorkRoles_userId_fkey"; + +-- AddForeignKey +ALTER TABLE "UserKey" ADD CONSTRAINT "UserKey_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserNostrKey" ADD CONSTRAINT "UserNostrKey_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserEmail" ADD CONSTRAINT "UserEmail_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UsersOnWorkRoles" ADD CONSTRAINT "UsersOnWorkRoles_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ProjectMember" ADD CONSTRAINT "ProjectMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TournamentParticipant" ADD CONSTRAINT "TournamentParticipant_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FoundersClubMember" ADD CONSTRAINT "FoundersClubMember_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserAction" ADD CONSTRAINT "UserAction_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserBadgeProgress" ADD CONSTRAINT "UserBadgeProgress_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserBadge" ADD CONSTRAINT "UserBadge_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "NostrBadgeRequest" ADD CONSTRAINT "NostrBadgeRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TournamentJudgingRoundJudge" ADD CONSTRAINT "TournamentJudgingRoundJudge_judge_id_fkey" FOREIGN KEY ("judge_id") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TournamentJudgingRoundJudgeScore" ADD CONSTRAINT "TournamentJudgingRoundJudgeScore_judge_id_fkey" FOREIGN KEY ("judge_id") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TournamentOrganizer" ADD CONSTRAINT "TournamentOrganizer_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 3b44ccb9..152a3537 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -48,7 +48,7 @@ model Vote { paid Boolean @default(false) user_id Int? - user User? @relation(fields: [user_id], references: [id]) + user User? @relation(fields: [user_id], references: [id], onDelete: SetNull) } // ----------------- @@ -109,7 +109,7 @@ model UserKey { name String @default("My new wallet key") createdAt DateTime @default(now()) - user User? @relation(fields: [user_id], references: [id]) + user User? @relation(fields: [user_id], references: [id], onDelete: Cascade) user_id Int? } @@ -120,7 +120,7 @@ model UserNostrKey { is_primary Boolean @default(false) is_default_generated_key Boolean @default(false) - user User? @relation(fields: [user_id], references: [id]) + user User? @relation(fields: [user_id], references: [id], onDelete: Cascade) user_id Int? } @@ -129,7 +129,7 @@ model UserEmail { email String @unique createdAt DateTime @default(now()) - user User? @relation(fields: [user_id], references: [id]) + user User? @relation(fields: [user_id], references: [id], onDelete: Cascade) user_id Int? } @@ -141,7 +141,7 @@ model Otp { } model UsersOnWorkRoles { - user User @relation(fields: [userId], references: [id]) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId Int role WorkRole @relation(fields: [roleId], references: [id]) roleId Int @@ -243,7 +243,7 @@ model ProjectRecruitRoles { model ProjectMember { project Project @relation(fields: [projectId], references: [id]) projectId Int - user User @relation(fields: [userId], references: [id]) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId Int role String // Admin | Maker | (new_roles_later) @@ -284,7 +284,7 @@ model Story { tags Tag[] - user User? @relation(fields: [user_id], references: [id]) + user User? @relation(fields: [user_id], references: [id], onDelete: SetNull) user_id Int? comments PostComment[] @relation("StoryComment") @@ -305,7 +305,7 @@ model Question { tags Tag[] - user User? @relation(fields: [user_id], references: [id]) + user User? @relation(fields: [user_id], references: [id], onDelete: SetNull) user_id Int? comments PostComment[] @relation("QuestionComment") @@ -322,7 +322,7 @@ model PostComment { parent_comment_id Int? parent_comment PostComment? @relation("PostComment_Replies", fields: [parent_comment_id], references: [id]) - user User? @relation(fields: [user_id], references: [id]) + user User? @relation(fields: [user_id], references: [id], onDelete: SetNull) user_id Int? story Story? @relation("StoryComment", fields: [story_id], references: [id]) @@ -363,7 +363,7 @@ model Donation { preimage String? paid Boolean @default(false) - donor User? @relation(fields: [donor_id], references: [id]) + donor User? @relation(fields: [donor_id], references: [id], onDelete: SetNull) donor_id Int? } @@ -492,7 +492,7 @@ model TournamentEvent { model TournamentParticipant { tournament Tournament @relation(fields: [tournament_id], references: [id]) tournament_id Int - user User @relation(fields: [user_id], references: [id]) + user User @relation(fields: [user_id], references: [id], onDelete: Cascade) user_id Int createdAt DateTime @default(now()) @@ -536,7 +536,7 @@ model FoundersClubInvitation { model FoundersClubMember { id Int @id @default(autoincrement()) email String - user User @relation(fields: [user_id], references: [id]) + user User @relation(fields: [user_id], references: [id], onDelete: Cascade) user_id Int @unique // relation scalar field (used in the `@relation` attribute above) } @@ -561,7 +561,7 @@ model UserAction { failReason String? - user User @relation(fields: [user_id], references: [id]) + user User @relation(fields: [user_id], references: [id], onDelete: Cascade) user_id Int createdAt DateTime @default(now()) @@ -596,7 +596,7 @@ model UserBadgeProgress { badge Badge @relation(fields: [badgeId], references: [id]) badgeId Int - user User @relation(fields: [userId], references: [id]) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId Int progress Int @default(0) @@ -608,7 +608,7 @@ model UserBadge { badge Badge @relation(fields: [badgeId], references: [id]) badgeId Int - user User @relation(fields: [userId], references: [id]) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId Int badgeAwardNostrEventId String? @@ -624,7 +624,7 @@ model NostrBadgeRequest { badge Badge @relation(fields: [badgeId], references: [id]) badgeId Int - user User @relation(fields: [userId], references: [id]) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId Int publicKeyToAward String @@ -668,7 +668,7 @@ model TournamentJudgingRoundJudge { round TournamentJudgingRound @relation(fields: [round_id], references: [id]) judge_id Int - judge User @relation(fields: [judge_id], references: [id]) + judge User @relation(fields: [judge_id], references: [id], onDelete: Cascade) @@unique([round_id, judge_id]) } @@ -680,7 +680,7 @@ model TournamentJudgingRoundJudgeScore { round TournamentJudgingRound @relation(fields: [round_id], references: [id]) judge_id Int - judge User @relation(fields: [judge_id], references: [id]) + judge User @relation(fields: [judge_id], references: [id], onDelete: Cascade) project_id Int project Project @relation(fields: [project_id], references: [id]) @@ -697,7 +697,7 @@ model TournamentOrganizer { tournament Tournament @relation(fields: [tournament_id], references: [id]) user_id Int - user User @relation(fields: [user_id], references: [id]) + user User @relation(fields: [user_id], references: [id], onDelete: Cascade) @@id([tournament_id, user_id]) } diff --git a/src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx b/src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx index c5c560be..bac45051 100644 --- a/src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx +++ b/src/features/Posts/Components/PostCard/BountyCard/BountyCard.tsx @@ -1,78 +1,107 @@ -import { Bounty } from "src/features/Posts/types" -import Header from "../Header/Header" -import { FiUsers } from "react-icons/fi" -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 { Author, Tag } from "src/graphql" +import { Bounty } from "src/features/Posts/types"; +import Header from "../Header/Header"; +import { FiUsers } from "react-icons/fi"; +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 { Author, Tag } from "src/graphql"; -export type BountyCardType = Pick & { - tags: Array> - author: Pick + tags: Array>; + author: Pick | null; }; interface Props { - bounty: BountyCardType + bounty: BountyCardType; } export default function BountyCard({ bounty }: Props) { + const handleApply = () => {}; - const handleApply = () => { - - } - - return ( -
- {bounty.cover_image && } -
-
-
-
- -

- Bounty {bounty.title} -

- - -
- -
-
- Reward: - {bounty.reward_amount} sats -
-

{bounty.excerpt}

- -
- {bounty.tags.map(tag => - {tag.title} - )} -
- -
-
- -
- {bounty.applicants_count} Applicants -
-
+ return ( +
+ {bounty.cover_image && ( + + )} +
+ {bounty.author && ( +
+ )} +
+
+ +

+ + + Bounty + {" "} + {bounty.title} + +

+ +
+ +
+
+ Reward: + + {bounty.reward_amount} sats + +
+

{bounty.excerpt}

+
+ {bounty.tags.map((tag) => ( + + {tag.title} + + ))} +
- -
+
+
+ +
+ {" "} + + {bounty.applicants_count} Applicants + +
- ) + + +
+
+ ); } diff --git a/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx b/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx index 6102ed22..74654470 100644 --- a/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx +++ b/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx @@ -1,77 +1,82 @@ -import VotesCount from "src/Components/VotesCount/VotesCount" -import { Question } from "src/features/Posts/types" -import Header from "../Header/Header" -import { FiUsers } from "react-icons/fi" -import Badge from "src/Components/Badge/Badge" -import { Link } from "react-router-dom" -import VoteButton from "src/Components/VoteButton/VoteButton" -import { Author, Tag } from "src/graphql" +import VotesCount from "src/Components/VotesCount/VotesCount"; +import { Question } from "src/features/Posts/types"; +import Header from "../Header/Header"; +import { FiUsers } from "react-icons/fi"; +import Badge from "src/Components/Badge/Badge"; +import { Link } from "react-router-dom"; +import VoteButton from "src/Components/VoteButton/VoteButton"; +import { Author, Tag } from "src/graphql"; -export type QuestionCardType = Pick & { - // comments: Array> - tags: Array> - author: Pick + // comments: Array> + tags: Array>; + author: Pick | null; }; interface Props { - question: QuestionCardType + question: QuestionCardType; } export default function QuestionCard({ question }: Props) { - return ( -
- {/* */} -
-
-
- -

{question.title}

- -
-

{question.excerpt}

+ return ( +
+ {/* */} +
+ {question.author && ( +
+ )} +
+ +

{question.title}

+ +
+

{question.excerpt}

-
- - Help - - {question.tags.map(tag => - {tag.title} - )} -
+
+ + Help + + {question.tags.map((tag) => ( + + {tag.title} + + ))} +
-
-
- - {/*
+
+
+ + {/*
{question.answers_count} Answers
*/} -
+
-
-
- {/* {question.comments.slice(0, 2).map(comment =>
+
+
+ {/* {question.comments.slice(0, 2).map(comment =>

{trimText(comment.body, 80)}

)} */} -
+
- {/*
+ {/*
See all {question.answers_count} comments
*/} -
-
- ) +
+
+ ); } diff --git a/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx b/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx index f48ebbb3..564e3540 100644 --- a/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx +++ b/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx @@ -30,7 +30,7 @@ export type StoryCardType = Pick< | "nostr_event_id" > & { tags: Array>; - author: Pick; + author: Pick | null; }; interface Props { @@ -58,16 +58,18 @@ export default function StoryCard({ type: "story", id: story.id, title: story.title, - username: story.author.name, + username: story.author?.name, }); return (
- + {story.author && ( + + )} {story.cover_image && ( -

Trending

-
    - { - trendingPosts.loading ? - Array(4).fill(0).map((_, idx) =>
  • - -

    -

    -
  • - ) - : - trendingPosts.data?.getTrendingPosts.map(post => { - return -
  • - -

    {post.title}

    -
  • - - } - )} -
-
- ) + return ( +
+

Trending

+
    + {trendingPosts.loading + ? Array(4) + .fill(0) + .map((_, idx) => ( +
  • + +

    + + +

    +
  • + )) + : trendingPosts.data?.getTrendingPosts.map((post) => { + return ( + +
  • + {post.author && ( + + )} +

    {post.title}

    +
  • + + ); + })} +
+
+ ); } diff --git a/src/features/Posts/pages/NostrPostDetailsPage/Components/AuthorCard/AuthorCard.stories.tsx b/src/features/Posts/pages/NostrPostDetailsPage/Components/AuthorCard/AuthorCard.stories.tsx index 34a5607d..cbce4a8d 100644 --- a/src/features/Posts/pages/NostrPostDetailsPage/Components/AuthorCard/AuthorCard.stories.tsx +++ b/src/features/Posts/pages/NostrPostDetailsPage/Components/AuthorCard/AuthorCard.stories.tsx @@ -1,22 +1,23 @@ -import { ComponentStory, ComponentMeta } from '@storybook/react'; -import { MOCK_DATA } from 'src/mocks/data'; +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import { MOCK_DATA } from "src/mocks/data"; -import AuthorCard from './AuthorCard'; +import AuthorCard from "./AuthorCard"; export default { - title: 'Posts/Post Details Page/Components/AuthorCard', - component: AuthorCard, - argTypes: { - backgroundColor: { control: 'color' }, - }, + title: "Posts/Post Details Page/Components/AuthorCard", + component: AuthorCard, + argTypes: { + backgroundColor: { control: "color" }, + }, } as ComponentMeta; - -const Template: ComponentStory = (args) =>
+const Template: ComponentStory = (args) => ( +
+ +
+); export const Default = Template.bind({}); Default.args = { - author: MOCK_DATA['posts'].stories[0].author -} - - + author: MOCK_DATA["posts"].stories[0].author!, +}; diff --git a/src/features/Posts/pages/PostDetailsPage/Components/AuthorCard/AuthorCard.stories.tsx b/src/features/Posts/pages/PostDetailsPage/Components/AuthorCard/AuthorCard.stories.tsx index 34a5607d..cbce4a8d 100644 --- a/src/features/Posts/pages/PostDetailsPage/Components/AuthorCard/AuthorCard.stories.tsx +++ b/src/features/Posts/pages/PostDetailsPage/Components/AuthorCard/AuthorCard.stories.tsx @@ -1,22 +1,23 @@ -import { ComponentStory, ComponentMeta } from '@storybook/react'; -import { MOCK_DATA } from 'src/mocks/data'; +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import { MOCK_DATA } from "src/mocks/data"; -import AuthorCard from './AuthorCard'; +import AuthorCard from "./AuthorCard"; export default { - title: 'Posts/Post Details Page/Components/AuthorCard', - component: AuthorCard, - argTypes: { - backgroundColor: { control: 'color' }, - }, + title: "Posts/Post Details Page/Components/AuthorCard", + component: AuthorCard, + argTypes: { + backgroundColor: { control: "color" }, + }, } as ComponentMeta; - -const Template: ComponentStory = (args) =>
+const Template: ComponentStory = (args) => ( +
+ +
+); export const Default = Template.bind({}); Default.args = { - author: MOCK_DATA['posts'].stories[0].author -} - - + author: MOCK_DATA["posts"].stories[0].author!, +}; diff --git a/src/features/Posts/pages/PostDetailsPage/Components/BountyPageContent/BountyPageContent.tsx b/src/features/Posts/pages/PostDetailsPage/Components/BountyPageContent/BountyPageContent.tsx index ff3ce98d..1aa5aba4 100644 --- a/src/features/Posts/pages/PostDetailsPage/Components/BountyPageContent/BountyPageContent.tsx +++ b/src/features/Posts/pages/PostDetailsPage/Components/BountyPageContent/BountyPageContent.tsx @@ -1,7 +1,7 @@ -import Header from "src/features/Posts/Components/PostCard/Header/Header" -import { Bounty, } from "src/features/Posts/types" -import { marked } from 'marked'; -import styles from '../PageContent/styles.module.scss' +import Header from "src/features/Posts/Components/PostCard/Header/Header"; +import { Bounty } from "src/features/Posts/types"; +import { marked } from "marked"; +import styles from "../PageContent/styles.module.scss"; import Badge from "src/Components/Badge/Badge"; import { BiComment } from "react-icons/bi"; import VotesCount from "src/Components/VotesCount/VotesCount"; @@ -12,53 +12,84 @@ import VoteButton from "src/Components/VoteButton/VoteButton"; import { RiFlashlightLine } from "react-icons/ri"; import { numberFormatter } from "src/utils/helperFunctions"; - interface Props { - bounty: Bounty + bounty: Bounty; } export default function BountyPageContent({ bounty }: Props) { - return ( -
- - {/* Header */} -
-
-

{bounty.title} Bounty

-
- Reward: - {bounty.reward_amount} sats -
-
-
- {numberFormatter(bounty.votes_count)} votes -
-
- 32 Comments -
-
-
- - - -
-
-
-
- {/* Body */} -
- {bounty.tags.map(tag => - {tag.title} - )} -
- {/* Applicants */} - + return ( +
+ {/* Header */} +
+ {bounty.author && ( +
+ )} +

+ {bounty.title}{" "} + + Bounty + +

+
+ Reward: + + {bounty.reward_amount} sats + +
+
+
+ {" "} + + {numberFormatter(bounty.votes_count)} votes + +
+
+ {" "} + 32 Comments +
+
+
+ + +
- ) +
+
+ {/* Body */} +
+ {bounty.tags.map((tag) => ( + + {tag.title} + + ))} +
+ {/* Applicants */} + +
+ ); } diff --git a/src/features/Posts/pages/PostDetailsPage/Components/QuestionPageContent/QuestionPageContent.tsx b/src/features/Posts/pages/PostDetailsPage/Components/QuestionPageContent/QuestionPageContent.tsx index e3d96ba8..0c38f74c 100644 --- a/src/features/Posts/pages/PostDetailsPage/Components/QuestionPageContent/QuestionPageContent.tsx +++ b/src/features/Posts/pages/PostDetailsPage/Components/QuestionPageContent/QuestionPageContent.tsx @@ -22,12 +22,14 @@ export default function QuestionPageContent({ question }: Props) { className="bg-white p-32 border-2 border-gray-200 rounded-16" >
-
+ {question.author && ( +
+ )}

{question.title}

{question.tags.map((tag) => ( diff --git a/src/features/Posts/pages/PostDetailsPage/Components/StoryPageContent/StoryPageContent.tsx b/src/features/Posts/pages/PostDetailsPage/Components/StoryPageContent/StoryPageContent.tsx index dc225c80..6244b170 100644 --- a/src/features/Posts/pages/PostDetailsPage/Components/StoryPageContent/StoryPageContent.tsx +++ b/src/features/Posts/pages/PostDetailsPage/Components/StoryPageContent/StoryPageContent.tsx @@ -54,11 +54,13 @@ function StoryPageContent({ story }: Props) {
- + {story.author && ( + + )}
{story.nostr_event_id && ( - {curUser?.id === story.author.id && ( + {curUser?.id && curUser.id === story.author?.id && ( diff --git a/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx b/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx index d9a76597..aa8fc171 100644 --- a/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx +++ b/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx @@ -53,7 +53,7 @@ export default function PostDetailsPage(props: Props) { @@ -62,7 +62,7 @@ export default function PostDetailsPage(props: Props) {
- + {post.author && }
)} diff --git a/src/graphql/index.tsx b/src/graphql/index.tsx index cf78acea..6ab20294 100644 --- a/src/graphql/index.tsx +++ b/src/graphql/index.tsx @@ -77,7 +77,7 @@ export type Bounty = PostBase & { __typename?: 'Bounty'; applicants_count: Scalars['Int']; applications: Array; - author: User; + author: Maybe; body: Scalars['String']; cover_image: Maybe; createdAt: Scalars['Date']; @@ -466,7 +466,7 @@ export type PostBase = { export type PostComment = { __typename?: 'PostComment'; - author: User; + author: Maybe; body: Scalars['String']; created_at: Scalars['Date']; id: Scalars['Int']; @@ -777,7 +777,7 @@ export type QueryUsersByNostrKeysArgs = { export type Question = PostBase & { __typename?: 'Question'; - author: User; + author: Maybe; body: Scalars['String']; createdAt: Scalars['Date']; excerpt: Scalars['String']; @@ -806,7 +806,7 @@ export enum RoleLevelEnum { export type Story = PostBase & { __typename?: 'Story'; - author: User; + author: Maybe; body: Scalars['String']; comments: Array; comments_count: Scalars['Int']; @@ -1327,7 +1327,7 @@ export type RecentProjectsInTagQuery = { __typename?: 'Query', recentProjectsInT export type TrendingPostsQueryVariables = Exact<{ [key: string]: never; }>; -export type TrendingPostsQuery = { __typename?: 'Query', getTrendingPosts: Array<{ __typename?: 'Bounty', id: number, title: string, author: { __typename?: 'User', id: number, avatar: string } } | { __typename?: 'Question', id: number, title: string, author: { __typename?: 'User', id: number, avatar: string } } | { __typename?: 'Story', id: number, title: string, author: { __typename?: 'User', id: number, avatar: string } }> }; +export type TrendingPostsQuery = { __typename?: 'Query', getTrendingPosts: Array<{ __typename?: 'Bounty', id: number, title: string, author: { __typename?: 'User', id: number, avatar: string } | null } | { __typename?: 'Question', id: number, title: string, author: { __typename?: 'User', id: number, avatar: string } | null } | { __typename?: 'Story', id: number, title: string, author: { __typename?: 'User', id: number, avatar: string } | null }> }; export type GetAllTopicsQueryVariables = Exact<{ [key: string]: never; }>; @@ -1373,7 +1373,7 @@ export type FeedQueryVariables = Exact<{ }>; -export type FeedQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, author: { __typename?: 'User', 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, excerpt: string, votes_count: number, type: string, cover_image: string | null, comments_count: number, nostr_event_id: string | null, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, project: { __typename?: 'Project', id: number, title: string, thumbnail_image: string | null, hashtag: string } | null }> }; +export type FeedQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any } | null, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any } | null, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string | null, comments_count: number, nostr_event_id: string | null, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any } | null, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, project: { __typename?: 'Project', id: number, title: string, thumbnail_image: string | null, hashtag: string } | null }> }; export type PostDetailsQueryVariables = Exact<{ id: Scalars['Int']; @@ -1381,7 +1381,7 @@ export type PostDetailsQueryVariables = Exact<{ }>; -export type PostDetailsQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, excerpt: string, createdAt: any, body: string, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, primary_nostr_key: string | null }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, votes: { __typename?: 'Votes', total: number, total_anonymous_votes: number, voters: Array<{ __typename?: 'Voter', amount_voted: number, user: { __typename?: 'User', id: number, name: string, avatar: string } }> }, applications: Array<{ __typename?: 'BountyApplication', id: number, date: string, workplan: string, author: { __typename?: 'User', id: number, name: string, avatar: string } }> } | { __typename?: 'Question', id: number, title: string, excerpt: string, createdAt: any, body: string, type: string, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, primary_nostr_key: string | null }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, votes: { __typename?: 'Votes', total: number, total_anonymous_votes: number, voters: Array<{ __typename?: 'Voter', amount_voted: number, user: { __typename?: 'User', id: number, name: string, avatar: string } }> } } | { __typename?: 'Story', id: number, title: string, excerpt: string, createdAt: any, body: string, type: string, cover_image: string | null, is_published: boolean | null, nostr_event_id: string | null, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, primary_nostr_key: string | null }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, votes: { __typename?: 'Votes', total: number, total_anonymous_votes: number, voters: Array<{ __typename?: 'Voter', amount_voted: number, user: { __typename?: 'User', id: number, name: string, avatar: string } }> }, project: { __typename?: 'Project', id: number, title: string, thumbnail_image: string | null, hashtag: string } | null } }; +export type PostDetailsQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, excerpt: string, createdAt: any, body: string, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, primary_nostr_key: string | null } | null, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, votes: { __typename?: 'Votes', total: number, total_anonymous_votes: number, voters: Array<{ __typename?: 'Voter', amount_voted: number, user: { __typename?: 'User', id: number, name: string, avatar: string } }> }, applications: Array<{ __typename?: 'BountyApplication', id: number, date: string, workplan: string, author: { __typename?: 'User', id: number, name: string, avatar: string } }> } | { __typename?: 'Question', id: number, title: string, excerpt: string, createdAt: any, body: string, type: string, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, primary_nostr_key: string | null } | null, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, votes: { __typename?: 'Votes', total: number, total_anonymous_votes: number, voters: Array<{ __typename?: 'Voter', amount_voted: number, user: { __typename?: 'User', id: number, name: string, avatar: string } }> } } | { __typename?: 'Story', id: number, title: string, excerpt: string, createdAt: any, body: string, type: string, cover_image: string | null, is_published: boolean | null, nostr_event_id: string | null, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, primary_nostr_key: string | null } | null, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, votes: { __typename?: 'Votes', total: number, total_anonymous_votes: number, voters: Array<{ __typename?: 'Voter', amount_voted: number, user: { __typename?: 'User', id: number, name: string, avatar: string } }> }, project: { __typename?: 'Project', id: number, title: string, thumbnail_image: string | null, hashtag: string } | null } }; export type GetTagInfoQueryVariables = Exact<{ tag: InputMaybe; @@ -1398,7 +1398,7 @@ export type TagFeedQueryVariables = Exact<{ }>; -export type TagFeedQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, author: { __typename?: 'User', 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, excerpt: string, votes_count: number, type: string, cover_image: string | null, comments_count: number, nostr_event_id: string | null, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, project: { __typename?: 'Project', id: number, title: string, thumbnail_image: string | null, hashtag: string } | null }> }; +export type TagFeedQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any } | null, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any } | null, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string | null, comments_count: number, nostr_event_id: string | null, author: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any } | null, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, project: { __typename?: 'Project', id: number, title: string, thumbnail_image: string | null, hashtag: string } | null }> }; export type UserBasicInfoFragment = { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, primary_nostr_key: string | null, role: string | null, jobTitle: string | null, lightning_address: string | null, website: string | null, twitter: string | null, discord: string | null, github: string | null, linkedin: string | null, bio: string | null, location: string | null, last_seen_notification_time: any };