Skip to content

Commit

Permalink
feat: connect questions to video
Browse files Browse the repository at this point in the history
  • Loading branch information
ezhil56x committed Sep 28, 2024
1 parent 1ceeb14 commit 0960e39
Show file tree
Hide file tree
Showing 15 changed files with 247 additions and 52 deletions.
58 changes: 55 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- AlterTable
ALTER TABLE "Question" ADD COLUMN "videoId" INTEGER;

-- CreateIndex
CREATE INDEX "Question_videoId_idx" ON "Question"("videoId");

-- AddForeignKey
ALTER TABLE "Question" ADD CONSTRAINT "Question_videoId_fkey" FOREIGN KEY ("videoId") REFERENCES "Content"("id") ON DELETE SET NULL ON UPDATE CASCADE;
4 changes: 4 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ model Content {
comments Comment[]
commentsCount Int @default(0)
bookmark Bookmark[]
questions Question[]
}

model CourseContent {
Expand Down Expand Up @@ -266,9 +267,12 @@ model Question {
answers Answer[]
votes Vote[]
tags String[]
video Content? @relation(fields: [videoId], references: [id])
videoId Int?
updatedAt DateTime @updatedAt
@@index([authorId])
@@index([videoId])
}

model Answer {
Expand Down
3 changes: 2 additions & 1 deletion src/actions/question/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const createQuestionHandler = async (
};
}

const { title, content, tags } = data;
const { title, content, tags, videoId } = data;

// Create initial slug
let slug = generateHandle(title);
Expand Down Expand Up @@ -61,6 +61,7 @@ const createQuestionHandler = async (
title,
content,
tags,
videoId,
authorId: session.user.id,
slug, // Include the slug
},
Expand Down
2 changes: 2 additions & 0 deletions src/actions/question/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ export const QuestionInsertSchema = z.object({
title: z.string().min(5, 'Question title too short'),
content: z.string().min(0, 'Question content too short'),
tags: z.array(z.string()).optional(),
videoId: z.number().optional(),
});

export const QuestionUpdateSchema = z.object({
title: z.string().min(5, 'Question title too short'),
content: z.string().min(0, 'Question content too short'),
tags: z.array(z.string()).optional(),
videoId: z.number().optional(),
questionId: z.number(),
});
export const QuestionDeleteSchema = z.object({
Expand Down
15 changes: 14 additions & 1 deletion src/actions/question/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ export interface QuestionQuery {
name: boolean;
};
};
video: {
select: {
id: boolean;
title: boolean;
};
};
votes: {
where: {
userId: string | undefined;
Expand All @@ -57,7 +63,7 @@ export interface QuestionQuery {
};
where?: {
authorId?: string;

videoId?: number;
title?: {
contains: string;
};
Expand All @@ -76,13 +82,20 @@ export interface Author {
email?: string | null;
}

export interface Video {
id: number;
title: string;
}

export interface ExtendedQuestion extends Question {
author: Author;
video: Video;
votes: any[];
}

export interface ExtendedAnswer extends Answer {
author: Author;
video: Video;
votes: any[];
responses: ExtendedAnswer[];
}
1 change: 1 addition & 0 deletions src/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface QueryParams {
page?: number;
tabtype?: TabType;
search?: string;
videoId?: number;
date?: string;
type?: CommentType;
parentId?: number;
Expand Down
6 changes: 6 additions & 0 deletions src/app/(main)/(pages)/question/[slug]/@question/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ const SingleQuestionPage = async ({
name: true,
},
},
video: {
select: {
id: true,
title: true,
},
},
votes: {
where: {
userId: sessionId,
Expand Down
32 changes: 22 additions & 10 deletions src/app/(main)/(pages)/question/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,32 @@ const getQuestionsWithQuery = async (
select: { userId: true, voteType: true },
},
author: { select: { id: true, name: true } },
video: {
select: {
id: true,
title: true,
},
},
},
};

const searchQuery = searchParams.search
? {
where: {
...additionalQuery.where,
title: {
contains: searchParams.search,
mode: 'insensitive',
const searchQuery =
searchParams.search || searchParams.videoId
? {
where: {
...additionalQuery.where,
...(searchParams.search && {
title: {
contains: searchParams.search,
mode: 'insensitive',
},
}),
...(searchParams.videoId && {
videoId: parseInt(searchParams.videoId.toString(), 10),
}),
},
},
}
: {};
}
: {};

const dateFilter = searchParams.date;
if (dateFilter) {
Expand Down
62 changes: 62 additions & 0 deletions src/components/NewPostDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { getUpdatedUrl, searchParamsToObject } from '@/lib/utils';
import { FormPostInput } from './posts/form/form-input';
import { FormPostErrors } from './posts/form/form-errors';
import { X } from 'lucide-react';
import SearchBar from './search/SearchBar';

export const NewPostDialog = () => {
const { theme } = useTheme();
Expand All @@ -29,6 +30,8 @@ export const NewPostDialog = () => {
const tagInputRef = useRef<HTMLInputElement | null>(null);
const [value, setValue] = useState<string>('**Hello world!!!**');
const [tags, setTags] = useState<string[]>([]);
const [videoId, setVideoId] = useState<string>('');
const [videoTitle, setVideoTitle] = useState<string>('');
const containerRef = useRef<HTMLDivElement>(null);
const { ref, onOpen, onClose } = useModal();
const handleMarkdownChange = (newValue?: string) => {
Expand All @@ -55,6 +58,8 @@ export const NewPostDialog = () => {
toast.success(`Question "${data.title}" created`);
formRef?.current?.reset();
setValue('');
setVideoId('');
setVideoTitle('');
router.push(`/question/${data.slug}`);
setTags([]);
handleOnCloseClick();
Expand All @@ -76,10 +81,12 @@ export const NewPostDialog = () => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const title = formData.get('title');
const videoId = formData.get('videoId');
execute({
title: title?.toString() || '',
content: value,
tags,
videoId: videoId ? parseInt(videoId.toString(), 10) : undefined,
});
};

Expand All @@ -106,6 +113,19 @@ export const NewPostDialog = () => {
setTags(tags.filter((t) => t !== tag));
};

const handleSearch = (
videoUrl?: string,
videoId?: number,
videoTitle?: string,
) => {
if (videoUrl && videoId && videoTitle) {
setVideoId(videoId.toString());
setVideoTitle(videoTitle);
} else {
toast.error('Something went wrong while selecting the video');
}
};

return (
<Modal ref={ref} onClose={handleOnCloseClick}>
<div className="fixed inset-0 bg-black/50 backdrop-blur-md" />
Expand Down Expand Up @@ -180,6 +200,48 @@ export const NewPostDialog = () => {
/>
</div>
</div>
<div className="flex w-full flex-col gap-2">
<h3 className="wmde-markdown-var text-lg font-bold tracking-tighter">
Link to a video
</h3>

{videoId ? (
<div className="flex w-full items-center gap-2">
<FormPostInput
id="videoTitle"
placeholder="Select a video from the search"
value={videoTitle}
errors={fieldErrors}
className="w-full"
disabled={true}
/>
<Button
type="button"
className="flex-shrink-0"
onClick={() => {
setVideoId('');
setVideoTitle('');
}}
>
Clear
</Button>
</div>
) : (
<SearchBar
onCardClick={handleSearch}
shouldRedirect={false}
/>
)}

{videoId && (
<FormPostInput
id="videoId"
value={videoId}
errors={fieldErrors}
type="hidden"
/>
)}
</div>

<div
data-color-mode={theme}
Expand Down
Loading

0 comments on commit 0960e39

Please sign in to comment.