Skip to content

Commit

Permalink
feat: added questions to frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
uptownhr committed Aug 20, 2023
1 parent 6e90fbf commit ac2b0d3
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 31 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ pnpm-debug.log*
!.yarn/releases
!.yarn/sdks
!.yarn/versions

*.key*
61 changes: 45 additions & 16 deletions apps/backend/src/app/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Body,
Controller,
Get,
HttpException,
Param,
ParseIntPipe,
Post,
Expand All @@ -17,6 +18,7 @@ import {
Answer,
CreatePageInput,
Page,
PageWithQuestions,
Question,
} from './app.model';
import { ApiResponse } from '@nestjs/swagger';
Expand Down Expand Up @@ -81,37 +83,64 @@ export class AppController {
};
}

@ApiResponse({ type: Question, status: 200, isArray: true })
@ApiResponse({ type: Page, status: 200 })
@Get('page/:id')
async getPage(id: number): Promise<Page> {
const page = await this.lovDb.page.findUnique({
where: {
id,
},
});

if (!page) {
throw new HttpException('Page not found', 404);
}

return page;
}

@ApiResponse({ type: PageWithQuestions, status: 200 })
@Get('page/:id/questions')
async getPageQuestions(
@Param('id', ParseIntPipe) pageId: number
): Promise<Question[]> {
const questions = await this.lovDb.question.findMany({
): Promise<PageWithQuestions> {
const page = await this.lovDb.page.findUnique({
where: {
pageId,
id: pageId,
},
select: {
id: true,
title: true,
votes: {
select: {
id: true,
},
},

answers: {
select: {
id: true,
include: {
questions: {
include: {
votes: {
select: {
id: true,
},
},
answers: {
select: {
id: true,
},
},
},
},
},
});

return questions.map((q) => ({
if (!page) {
throw new HttpException('Page not found', 404);
}

const mappedQuestions = page.questions.map((q) => ({
...q,
voteCount: q.votes.length,
answerCount: q.answers.length,
}));

return {
...page,
questions: mappedQuestions,
};
}

@ApiResponse({ type: Answer, status: 201 })
Expand Down
35 changes: 20 additions & 15 deletions apps/backend/src/app/app.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,47 @@ export class CreatePageInput {
title: string;
}

export class Page {
@ApiProperty()
id: number;

export class AddQuestionInput {
@ApiProperty()
title: string;

@ApiProperty()
slug: string;

pageId: number;
}
export class Question {
@ApiProperty()
createdAt: Date;
id: number;

@ApiProperty()
updatedAt: Date;
}
title: string;

export class AddQuestionInput {
@ApiProperty()
title: string;
answerCount: number;

@ApiProperty()
pageId: number;
voteCount: number;
}
export class Question {

export class Page {
@ApiProperty()
id: number;

@ApiProperty()
title: string;

@ApiProperty()
answerCount: number;
slug: string;

@ApiProperty()
voteCount: number;
createdAt: Date;

@ApiProperty()
updatedAt: Date;
}

export class PageWithQuestions extends Page {
@ApiProperty({ type: Question, isArray: true })
questions: Question[];
}

export class AddAnswerInput {
Expand Down
26 changes: 26 additions & 0 deletions apps/website/src/modules/qna/NewTopic.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script>
import {questionApi} from "@modules/qna/api";
let form = {
topic: null
}
async function createTopic() {
const response = await questionApi('/page', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: form.topic
})
})
window.location.href=`topic?id=${response.id}`
}
</script>

<form on:submit|preventDefault={createTopic}>
<input type="text" placeholder="Topic" bind:value={form.topic}>
<input type="submit" value="Create">
</form>
54 changes: 54 additions & 0 deletions apps/website/src/modules/qna/Topic.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<script>
import {onMount} from 'svelte'
import {questionApi} from "@modules/qna/api";
const url = new URL(window.location.href)
const id = parseInt(url.searchParams.get('id'))
let topic
onMount(async () => {
topic = await questionApi(`/page/${id}/questions`);
})
let form = {
question: null
}
async function addQuestion(x) {
const question = await questionApi(`/question`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: form.question,
pageId: id
})
});
topic.questions = [...topic.questions, question]
form.question = null
}
</script>

<div>
{#if topic}
<h1>{topic.title}</h1>
{/if}
<form on:submit|preventDefault={() => addQuestion('test')}>
<input type="text" bind:value={form.question} placeholder="What is your question?">
<input type="submit" value="Add Question" />
</form>

{#if topic}
<ul>
{#each topic.questions as question}
<li>
{question.title} <br />
Votes: {question.voteCount} | Answers: {question.answerCount}
</li>
{/each}
</ul>
{/if}
</div>
19 changes: 19 additions & 0 deletions apps/website/src/modules/qna/Topics.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script>
import { onMount } from 'svelte';
import { questionApi } from '@modules/qna/api';
let topics = []
onMount(async () => {
topics = await questionApi('/pages');
});
</script>

<div>
<h2>Topics <a href="/tools/question-answer/new" style="float: right; font-size: 1rem">+ New Topic</a></h2>
<ul>
{#each topics as topic (topic.id)}
<li><a href="/tools/question-answer/topic?id={topic.id}">{topic.title}</a></li>
{/each}
</ul>
</div>
5 changes: 5 additions & 0 deletions apps/website/src/modules/qna/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const baseUrl = import.meta.env.PUBLIC_API_URL;

export function questionApi(endPoint: string, options: any) {
return fetch(`${baseUrl}${endPoint}`, options).then((res) => res.json());
}
1 change: 1 addition & 0 deletions apps/website/src/pages/tools.astro
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { SITE_TITLE, SITE_DESCRIPTION } from '../config';
<section>
<ul>
<li><a href="/tools/loan-amortization-schedule-generator">Loan Amortization Schedule Generator</a></li>
<li><a href="/tools/question-answer">Question and Answers</a></li>
</ul>
</section>
</main>
Expand Down
24 changes: 24 additions & 0 deletions apps/website/src/pages/tools/question-answer/index.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
import BaseHead from '../../../components/BaseHead.astro';
import Header from '../../../components/Header.astro';
import Footer from '../../../components/Footer.astro';
import { SITE_TITLE, SITE_DESCRIPTION } from '../../../config';
import Topics from "../../../modules/qna/Topics.svelte";
const pageTitle = 'Question and Answers';
---

<!DOCTYPE html>
<html lang="en">
<head>
<BaseHead title={pageTitle} description={SITE_DESCRIPTION} />
</head>
<body>
<Header title={SITE_TITLE} />
<main>
<h1>🏁 {pageTitle}</h1>
<Topics client:only />
</main>
<Footer />
</body>
</html>
23 changes: 23 additions & 0 deletions apps/website/src/pages/tools/question-answer/new.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
import BaseHead from '../../../components/BaseHead.astro';
import Header from '../../../components/Header.astro';
import Footer from '../../../components/Footer.astro';
import { SITE_TITLE, SITE_DESCRIPTION } from '../../../config';
import NewTopic from '@modules/qna/NewTopic.svelte';
const pageTitle = 'Question and Answers';
---

<!DOCTYPE html>
<html lang="en">
<head>
<BaseHead title={pageTitle} description={SITE_DESCRIPTION} />
</head>
<body>
<Header title={SITE_TITLE} />
<main>
<h1>🏁 {pageTitle}</h1>
<NewTopic client:only />
</main>
<Footer />
</body>
</html>
24 changes: 24 additions & 0 deletions apps/website/src/pages/tools/question-answer/topic.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
import BaseHead from '../../../components/BaseHead.astro';
import Header from '../../../components/Header.astro';
import Footer from '../../../components/Footer.astro';
import { SITE_TITLE, SITE_DESCRIPTION } from '../../../config';
import Topic from "@modules/qna/Topic.svelte";
const pageTitle = 'Question and Answers';
---

<!DOCTYPE html>
<html lang="en">
<head>
<BaseHead title={pageTitle} description={SITE_DESCRIPTION} />
</head>
<body>
<Header title={SITE_TITLE} />
<main>
<h1>🏁 {pageTitle}</h1>
<Topic client:only />
</main>
<Footer />
</body>
</html>
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"build": "astro build",
"preview": "astro preview",
"astro": "astro",
"frontend": "nx run website:dev",
"backend": "nx serve backend",
"backend:production": "nx run backend:serve:production"
},
Expand Down

0 comments on commit ac2b0d3

Please sign in to comment.