Skip to content

Commit

Permalink
Merge pull request #33 from Team-BomBomBom/feat/book_study_dashboard#…
Browse files Browse the repository at this point in the history
…BBB-99

Feat: #BBB-99 μ„œμ  μŠ€ν„°λ”” λŒ€μ‹œλ³΄λ“œ λ””μžμΈ
  • Loading branch information
msjang4 authored Aug 28, 2024
2 parents 11cf746 + df78ee3 commit 074508b
Show file tree
Hide file tree
Showing 19 changed files with 729 additions and 47 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
47 changes: 47 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
FROM node:20-alpine AS base

FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json package-lock.json ./
RUN npm ci

FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_PUBLIC_API_SERVER_URL https://www.dev-study.com
RUN npm run build

FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD node server.js
38 changes: 37 additions & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,50 @@
'use client';

import { Button } from '@/components/ui/button/button';
import { StudyIcon } from '@/components/ui/icon/icon';
import { userState } from '@/recoil/userAtom';
import { VideoIcon } from 'lucide-react';
import { useRecoilState } from 'recoil';

export default function Home() {
const [myData, setMyData] = useRecoilState(userState);
return (
<>
<div className="text-center">
{/* <div className="text-center">
{myData?.username + '둜 둜그인된 μƒνƒœμž…λ‹ˆλ‹€.'}
</div> */}
<div className="flex items-center justify-center min-h-screen bg-gradient-to-b from-white to-gray-300">
<div className="space-y-12">
<div className="ml-12 text-5xl grid grid-rows-3 grid-cols-2 gap-x-12 gap-y-3">
<b>κ°œλ°œμžλ“€μ˜</b>
<b>Dev&apos;s</b>
<b>깊이 μžˆλŠ”</b>
<b>Depth</b>
<b>μŠ€ν„°λ””</b>
<b>Study</b>
</div>
<div className="flex flex-col space-y-2 items-center">
<Button className="w-1/2 bg-gray-900 text-white py-6 px-6 rounded-lg shadow-md hover:bg-gray-600">
<div className="text-xl flex items-center justify-center space-x-2">
<StudyIcon className="w-7 h-7"></StudyIcon>
<p>μŠ€ν„°λ”” μ‹œμž‘ν•˜κΈ°</p>
</div>
</Button>
<Button className="w-1/2 bg-gray-900 text-white py-6 px-6 rounded-lg shadow-md hover:bg-gray-600">
<div className="text-xl flex items-center justify-center space-x-2">
<VideoIcon className="w-7 h-7"></VideoIcon>
<p>κ°•μ˜ λ‘˜λŸ¬λ³΄κΈ°</p>
</div>
</Button>
</div>
</div>
{/* <div className="relative">
<img
src="gray-hamster.png"
alt="hamster with laptop"
className="w-full max-w-md"
/>
</div> */}
</div>
</>
);
Expand Down
91 changes: 91 additions & 0 deletions app/post/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use client';
import {
Avatar,
AvatarFallback,
AvatarImage
} from '@/components/ui/avatar/avatar';
import { Button } from '@/components/ui/button/button';
import { Label } from '@/components/ui/label/label';
import { Textarea } from '@/components/ui/textarea/textarea';

export default function Post() {
return (
<div className="flex px-4 py-6 md:px-6 lg:py-16 md:py-12 ">
<article className="prose prose-gray mx-auto dark:prose-invert w-[600px]">
<div className="space-y-2 not-prose mb-3">
<h1 className="text-4xl font-extrabold tracking-tight lg:text-5xl lg:leading-[3.5rem]">
μŠ€ν„°λ”” μž…μž₯ μ „ 필독
</h1>
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
<Avatar className="w-8 h-8 border">
<AvatarImage src="/placeholder-user.jpg" alt="@shadcn" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<div className="text-sm font-medium">λ©˜ν† </div>
</div>
<div className="text-muted-foreground text-sm">2024. 08. 13</div>
</div>
</div>
<p>1. 9μ‹œ 1뢄은 9μ‹œκ°€ μ•„λ‹ˆλ‹€</p>
<p>2. 싀행은 수직적 λ¬Έν™”λŠ” μˆ˜ν‰μ </p>
<p>3. μž‘λ‹΄μ„ 많이 λ‚˜λˆ„λŠ” 것이 경쟁λ ₯이닀</p>
<p>4. νœ΄κ°€λ‚˜ 퇴근 μ‹œ λˆˆμΉ˜μ£ΌλŠ” 농담을 ν•˜μ§€ μ•ŠλŠ”λ‹€</p>
<p>5. λ³΄κ³ λŠ” νŒ©νŠΈμ— κΈ°λ°˜ν•œλ‹€</p>
<p>6. νšŒμ‹μ€ 100% 자율적으둜 μ°Έμ„ν•œλ‹€</p>
<br></br>
<h2 className="text-lg">λŒ“κΈ€</h2>
<div className="space-y-4 mt-3">
<div className="flex items-start gap-4">
<Avatar className="w-10 h-10 border">
<AvatarImage src="/placeholder-user.jpg" alt="@shadcn" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<div className="grid gap-1">
<div className="font-medium">μž₯민석</div>
<div className="text-muted-foreground">
μ „ 격주둜 ν•  것 같은데 κ°€λŠ₯ν• κΉŒμš”?
</div>
</div>
</div>
<div className="flex items-start gap-4">
<Avatar className="w-10 h-10 border">
<AvatarImage src="/placeholder-user.jpg" alt="@shadcn" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<div className="grid gap-1">
<div className="font-medium">μ΄ν˜„μ’…</div>
<div className="text-muted-foreground">ν™•μΈν–ˆμŠ΅λ‹ˆλ‹€!</div>
</div>
</div>
<div className="flex items-start gap-4">
<Avatar className="w-10 h-10 border">
<AvatarImage src="/placeholder-user.jpg" alt="@shadcn" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<div className="grid gap-1">
<div className="font-medium">μ†‘μŠΉν›ˆ</div>
<div className="text-muted-foreground">λ„΅ ν™•μΈν–ˆμŠ΅λ‹ˆλ‹€</div>
</div>
</div>
</div>
<div className="mt-8">
<form className="grid gap-4">
<div className="grid gap-2">
<Label htmlFor="comment">λŒ“κΈ€ μΆ”κ°€...</Label>
<Textarea id="comment" placeholder="..." rows={3} />
</div>
<div className="flex justify-end ">
<Button
type="submit"
className="hover:bg-gray-600 bg-gray-900 text-white"
>
μž‘μ„±
</Button>
</div>
</form>
</div>
</article>
</div>
);
}
33 changes: 20 additions & 13 deletions app/study/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@ import { useParams } from 'next/navigation';
import { useEffect, useState } from 'react';

import StudyDashBoard from '@/components/study/dashboard/dashboard';
import PostBoard from '@/components/study/post-board';
import JoinStudyDialog from '@/components/study/study-join-dialog';
import { Button } from '@/components/ui/button/button';
import Spinner from '@/components/ui/spinner/spinner';
import getStudyDetails from '@/lib/api/study/get-details';
import startStudy from '@/lib/api/study/start';
import { userState } from '@/recoil/userAtom';
import {
AlgorithmRound,
StudyDetails,
StudyStatus
} from '@/types/study/study-detail';
import { Round, StudyDetails, StudyStatus } from '@/types/study/study-detail';
import { toast } from 'react-toastify';
import { useRecoilState } from 'recoil';

Expand All @@ -25,11 +22,12 @@ export default function StudyPage() {
const studyId = Number(params.id);

const [details, setDetails] = useState<StudyDetails | undefined>();
const [round, setRound] = useState<AlgorithmRound | undefined>();
const [round, setRound] = useState<Round | undefined>();
const [isParticipant, setIsParticipant] = useState(false);
const [canStart, setCanStart] = useState(false);
const [myData, setMyData] = useRecoilState(userState);
const [trigger, setTrigger] = useState(Date.now());
const [showPostBoard, setShowPostBoard] = useState(false);

const handleStart = async () => {
try {
Expand Down Expand Up @@ -80,12 +78,16 @@ export default function StudyPage() {

return (
<div className="flex space-x-4 justify-center">
<StudyDashBoard
details={details}
studyId={studyId}
round={round}
setRound={setRound}
/>
{showPostBoard ? (
<PostBoard></PostBoard>
) : (
<StudyDashBoard
details={details}
studyId={studyId}
round={round}
setRound={setRound}
/>
)}
<div className="mt-4">
{isParticipant ? (
canStart ? (
Expand All @@ -102,7 +104,12 @@ export default function StudyPage() {
refresh={refresh}
/>
)}
<StudyAbout details={details} users={round.users} />
<StudyAbout
details={details}
users={round.users}
showPostBoard={showPostBoard}
setShowPostBoard={setShowPostBoard}
/>
</div>
</div>
);
Expand Down
57 changes: 56 additions & 1 deletion components/study/dashboard/about.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,25 @@ import {
AvatarFallback,
AvatarImage
} from '@/components/ui/avatar/avatar';
import {
BellIcon,
BoxIcon,
FilePenIcon,
LayoutGridIcon
} from '@/components/ui/icon/icon';
import { StudyType } from '@/constants/study/study';
import { StudyDetails, StudyMemberInfo } from '@/types/study/study-detail';

export default function StudyAbout({
details,
users
users,
showPostBoard,
setShowPostBoard
}: {
details: StudyDetails;
users: { [userId: number]: StudyMemberInfo };
showPostBoard: boolean;
setShowPostBoard: (arg0: boolean) => void;
}) {
const endDate = new Date(details.startDate);
endDate.setDate(endDate.getDate() + details.weeks * 7);
Expand All @@ -21,8 +32,26 @@ export default function StudyAbout({
<h2 className="text-xl font-bold">μ†Œκ°œ</h2>
<SettingsIcon className="w-5 h-5 text-muted-foreground" />
</div>

<p className="mt-2 text-muted-foreground">{details.introduce}</p>

<div className="mt-4 space-y-2">
<div
onClick={() => setShowPostBoard(!showPostBoard)}
className="group w-fit hover:text-gray-900 text-blue-600 flex items-center space-x-2"
>
{showPostBoard ? (
<>
<LayoutGridIcon className="group-hover:stroke-black stroke-blue w-5 h-5 text-muted-foreground"></LayoutGridIcon>
<b>λŒ€μ‹œλ³΄λ“œ </b>
</>
) : (
<>
<BellIcon className="group-hover:stroke-black stroke-blue w-5 h-5 text-muted-foreground"></BellIcon>
<b>곡지사항 </b>
</>
)}
</div>
<div className="flex items-center space-x-2">
<ActivityIcon className="w-5 h-5 text-muted-foreground" />
<b>
Expand Down Expand Up @@ -57,6 +86,32 @@ export default function StudyAbout({
<b>{details.reliabilityLimit}</b>
<span>이상</span>
</div>
{StudyType[details.studyType as keyof typeof StudyType] ===
StudyType.BOOK && (
<>
<div className="flex items-center space-x-2">
<BookIcon className="w-5 h-5 text-muted-foreground" />
{/* TODO details.book.title둜 λ³€κ²½ */}
<span>μžλ°”μ˜ 정석</span>
</div>

<div
onClick={() => {}}
className="group w-fit hover:text-gray-900 text-blue-600 flex items-center space-x-2"
>
<FilePenIcon className="group-hover:stroke-black stroke-blue w-5 h-5 text-muted-foreground"></FilePenIcon>
<b>과제 선택지 μˆ˜μ • </b>
</div>

<div
onClick={() => {}}
className="group w-fit hover:text-gray-900 text-blue-600 flex items-center space-x-2"
>
<BoxIcon className="group-hover:stroke-black stroke-blue w-5 h-5 text-muted-foreground"></BoxIcon>
<b>과제 νˆ¬ν‘œ </b>
</div>
</>
)}
</div>
<div className="mt-6">
<h3 className="text-lg font-bold">
Expand Down
Loading

0 comments on commit 074508b

Please sign in to comment.