Skip to content

Commit

Permalink
feat: merge dev
Browse files Browse the repository at this point in the history
  • Loading branch information
SeieunYoo committed Aug 20, 2024
2 parents 05a9232 + 55b19a2 commit 1129719
Show file tree
Hide file tree
Showing 40 changed files with 494 additions and 331 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
- main
- dev
pull_request:
types: [opened, ready_for_review, converted_to_draft]
types: [opened, ready_for_review, converted_to_draft, synchronize]
branches:
- main
- dev
Expand Down Expand Up @@ -34,7 +34,7 @@ jobs:
run_install: false

- name: Install dependencies
run: pnpm install
run: pnpm install --no-frozen-lockfile

- name: Run build
run: pnpm run build
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
},
"eslint.workingDirectories": [
{
"mode": "auto"
Expand Down
20 changes: 20 additions & 0 deletions apps/admin/apis/auth/dashboardApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { fetcher } from "@wow-class/utils";
import { apiPath } from "constants/apiPath";
import { tags } from "constants/tags";
import type { DashboardApiResponseDto } from "types/dtos/auth";

export const dashboardApi = {
getDashboardInfo: async () => {
const response = await fetcher.get<DashboardApiResponseDto>(
apiPath.dashboard,
{
next: { tags: [tags.dashboard] },
}
);

const studyRole = response.data?.member.studyRole;
const manageRole = response.data?.member.manageRole;

return { studyRole, manageRole };
},
};
6 changes: 6 additions & 0 deletions apps/admin/app/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"use client";
const ErrorPage = () => {
return <div>error</div>;
};

export default ErrorPage;
6 changes: 1 addition & 5 deletions apps/admin/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import "./global.css";
import "wowds-ui/styles.css";
import "@wow-class/ui/styles.css";

import Navbar from "components/Navbar";
import type { Metadata } from "next";

import { JotaiProvider } from "../components/JotaiProvider";
Expand All @@ -20,10 +19,7 @@ const RootLayout = ({
return (
<html lang="ko">
<body>
<JotaiProvider>
<Navbar />
{children}
</JotaiProvider>
<JotaiProvider>{children}</JotaiProvider>
</body>
</html>
);
Expand Down
5 changes: 5 additions & 0 deletions apps/admin/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const NotFound = () => {
return <div>요청하신 페이지를 찾을 수 없어요.</div>;
};

export default NotFound;
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { css } from "@styled-system/css";
import { Flex } from "@styled-system/jsx";
import Link from "next/link";
import isAdmin from "utils/isAdmin";
import { Plus } from "wowds-icons";

const CreateStudyButton = async () => {
const adminStatus = await isAdmin();

if (!adminStatus) return null;

return (
<Link href="studies/create-study">
<button className={createStudyButtonStyle}>
<Flex gap="xs">
<p className={css({ textStyle: "label1", color: "sub" })}>
새로운 스터디 개설하기
</p>
<div className={PlusIconStyle}>
<Plus height={14} width={14} />
</div>
</Flex>
</button>
</Link>
);
};

export default CreateStudyButton;

const createStudyButtonStyle = css({
width: "100%",
display: "flex",
justifyContent: "center",
borderRadius: "md",
borderStyle: "dashed",
borderWidth: "1px",
borderColor: "outline",
padding: "32px",
_hover: {
backgroundColor: "backgroundAlternative",
borderWidth: "0px",
cursor: "pointer",
},
});

const PlusIconStyle = css({
display: "flex",
justifyContent: "center",
alignItems: "center",
width: "20px",
height: "20px",
borderRadius: "full",
backgroundColor: "primary",
color: "white",
});
5 changes: 5 additions & 0 deletions apps/admin/app/studies/create-study/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const CreateStudyPage = () => {
return <div>스터디 생성</div>;
};

export default CreateStudyPage;
20 changes: 20 additions & 0 deletions apps/admin/app/studies/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Flex, styled } from "@styled-system/jsx";
import Navbar from "components/Navbar";
const StudiesLayout = ({
children,
}: Readonly<{
children: React.ReactNode;
}>) => {
return (
<>
<Navbar />
<styled.div padding="54px 101px" width="100%">
<Flex direction="column" gap="sm" width="100%">
{children}
</Flex>
</styled.div>
</>
);
};

export default StudiesLayout;
18 changes: 15 additions & 3 deletions apps/admin/app/studies/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
const Studies = () => {
return <div>Studies</div>;
import { css } from "@styled-system/css";
import { Flex } from "@styled-system/jsx";

import CreateStudyButton from "./create-study/_components/CreateStudyButton";

const StudiesPage = () => {
return (
<>
<Flex align="center" justifyContent="space-between">
<p className={css({ textStyle: "h1" })}>개설된 스터디</p>
</Flex>
<CreateStudyButton />
</>
);
};

export default Studies;
export default StudiesPage;
1 change: 1 addition & 0 deletions apps/admin/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export default Navbar;

const navbarContainerStyle = css({
width: "250px",
minWidth: "250px",
minHeight: "100vh",
paddingTop: "54px",
borderRightWidth: "arrow",
Expand Down
3 changes: 3 additions & 0 deletions apps/admin/constants/apiPath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const enum apiPath {
dashboard = "/onboarding/members/me/dashboard",
}
3 changes: 3 additions & 0 deletions apps/admin/constants/tags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const enum tags {
dashboard = "dashboard",
}
32 changes: 32 additions & 0 deletions apps/admin/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { dashboardApi } from "apis/auth/dashboardApi";
import { cookies } from "next/headers";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";

export const config = {
matcher: ["/studies/:path*", "/participants/:path*"],
};

const middleware = async (req: NextRequest) => {
const cookieStore = cookies();
const accessToken = cookieStore.get("accessToken")?.value;

if (!accessToken) {
return NextResponse.redirect(new URL("/not-found", req.url));
}

const { studyRole, manageRole } = await dashboardApi.getDashboardInfo();

if (studyRole === "STUDENT" && manageRole === "NONE") {
const url =
process.env.NODE_ENV === "production"
? process.env.CLIENT_PROD_URL
: process.env.CLIENT_DEV_URL;

return NextResponse.redirect(new URL("/auth", url));
}

return NextResponse.next();
};

export default middleware;
47 changes: 47 additions & 0 deletions apps/admin/types/dtos/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type { StatusType } from "../entities/auth";

export interface DashboardApiResponseDto {
member: {
memberId: number;
role: "GUEST" | "ADMIN" | "REGULAR";
manageRole: "ADMIN" | "NONE";
studyRole: "MENTOR" | "STUDENT";
basicInfo: {
name: string;
studentId: string;
email: string;
department: string;
phone: string;
discordUsername: string;
nickname: string;
};
associateRequirement: {
univStatus: StatusType;
discordStatus: Extract<StatusType, "UNSATISFIED" | "SATISFIED">;
bevyStatus: Extract<StatusType, "UNSATISFIED" | "SATISFIED">;
infoStatus: Extract<StatusType, "UNSATISFIED" | "SATISFIED">;
};
};
currentRecruitmentRound: {
recruitmentId: number;
name: string;
period: {
startDate: string;
endDate: string;
open: boolean;
};
fee: number;
roundType: "FIRST" | "SECOND";
roundTypeValue: string;
};
currentMembership: {
membershipId: number;
memberId: number;
recruitmentId: number;
regularRequirement: {
paymentStatus: Extract<StatusType, "UNSATISFIED" | "SATISFIED">;
paymentSatisfied: boolean;
allSatisfied: boolean;
};
};
}
1 change: 1 addition & 0 deletions apps/admin/types/entities/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type StatusType = "UNSATISFIED" | "IN_PROGRESS" | "SATISFIED";
3 changes: 3 additions & 0 deletions apps/admin/types/role.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type ManageRole = "ADMIN" | "NONE";
export type StudyRole = "MENTOR" | "STUDENT";
export type UserRoleType = "GUEST" | "ASSOCIATE" | "REGULAR";
2 changes: 2 additions & 0 deletions apps/admin/types/status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export type Status = "UNSATISFIED" | "SATISFIED";
export type UnivEmailStatus = "IN_PROGRESS" | "UNSATISFIED" | "SATISFIED";
33 changes: 33 additions & 0 deletions apps/admin/types/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { ManageRole, StudyRole, UserRoleType } from "./role";
import type { Status, UnivEmailStatus } from "./status";

export type User = {
memberId: string; // C000000 (학번)
role: UserRoleType;
basicInfo: UserBasicInfo;
manageRole: ManageRole;
studyRole: StudyRole;
associateRequirement: {
univStatus: UnivEmailStatus;
discordStatus: Status;
bevyStatus: Status;
infoStatus: Status;
};
};

export type AssociateRequirement = {
univStatus: UnivEmailStatus;
discordStatus: Status;
bevyStatus: Status;
infoStatus: Status;
};

export type UserBasicInfo = {
name: string;
studentId: string;
email: string;
department: string;
phone: string;
discordUsername: string;
nickname: string;
};
8 changes: 8 additions & 0 deletions apps/admin/utils/isAdmin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { dashboardApi } from "apis/auth/dashboardApi";

const isAdmin = async (): Promise<boolean> => {
const { manageRole } = await dashboardApi.getDashboardInfo();
return manageRole === "ADMIN";
};

export default isAdmin;
8 changes: 0 additions & 8 deletions apps/client/apis/dashboardApi.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
import { fetcher } from "@wow-class/utils";
import { apiPath } from "constants/apiPath";
import { tags } from "constants/tags";
import { cookies } from "next/headers";
import type { DashboardApiResponseDto } from "types/dtos/auth";

export const dashboardApi = {
getDashboardInfo: async () => {
const cookieStore = cookies();
const accessToken = cookieStore.get("accessToken")?.value;

// NOTE: middleware에서 호출하기 위해서 별도로 헤더 주입
const response = await fetcher.get<DashboardApiResponseDto>(
apiPath.dashboard,
{
next: { tags: [tags.dashboard] },
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);

Expand Down
15 changes: 3 additions & 12 deletions apps/client/apis/studyApplyApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const studyApplyApi = {
apiPath.applyStudy,
{
next: { tags: [tags.studyApply] },
cache: "force-cache",
}
);

Expand All @@ -20,21 +21,11 @@ export const studyApplyApi = {
null
);

if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData);
}

return response.data;
return { success: response.ok };
},
cancelStudyApplication: async (studyId: number) => {
const response = await fetcher.delete(`${apiPath.applyStudy}/${studyId}`);

if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData);
}

return response.data;
return { success: response.ok };
},
};
Loading

0 comments on commit 1129719

Please sign in to comment.