Skip to content

Commit e098fc1

Browse files
committed
[Add] semester filter
1 parent 554bc3b commit e098fc1

File tree

6 files changed

+245
-0
lines changed

6 files changed

+245
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* セメスターフィルターのコンポーネント
3+
*/
4+
5+
"use client";
6+
import React from "react";
7+
import { Semester } from "@/app/type";
8+
import { FlagButton } from "../UI/FlagButton";
9+
10+
/**
11+
* セメスターフィルターのプロパティ
12+
*/
13+
interface SemesterProp {
14+
selectedSemesters?: Semester[]; // 選択されているセメスター
15+
setSelectedSemesters: (semesters: Semester[]) => void;
16+
}
17+
18+
/**
19+
* セメスターフィルターのコンポーネント
20+
* @param prop セメスターフィルターのプロパティ
21+
* @returns コンポーネント
22+
*/
23+
export const SemestersCheckbox: React.FC<SemesterProp> = (
24+
prop: SemesterProp,
25+
) => {
26+
const selectedSemesters = prop.selectedSemesters ?? [];
27+
28+
// ボタンがクリックされたときの関数
29+
const onClick = (semester: Semester) => {
30+
if (selectedSemesters.includes(semester)) {
31+
prop.setSelectedSemesters(
32+
selectedSemesters.filter((s) => s !== semester),
33+
);
34+
} else {
35+
prop.setSelectedSemesters([...selectedSemesters, semester]);
36+
}
37+
};
38+
39+
return (
40+
<div className="grid grid-cols-4 gap-2">
41+
<FlagButton
42+
label={"S1"}
43+
isSelected={selectedSemesters.includes("S1")}
44+
onClick={() => onClick("S1")}
45+
className="aspect-square"
46+
/>
47+
<FlagButton
48+
label={"S2"}
49+
isSelected={selectedSemesters.includes("S2")}
50+
onClick={() => onClick("S2")}
51+
className="aspect-square"
52+
/>
53+
<FlagButton
54+
label={"A1"}
55+
isSelected={selectedSemesters.includes("A1")}
56+
onClick={() => onClick("A1")}
57+
className="aspect-square"
58+
/>
59+
<FlagButton
60+
label={"A2"}
61+
isSelected={selectedSemesters.includes("A2")}
62+
onClick={() => onClick("A2")}
63+
className="aspect-square"
64+
/>
65+
<FlagButton
66+
label={"S"}
67+
isSelected={selectedSemesters.includes("S")}
68+
onClick={() => onClick("S")}
69+
className="col-span-2"
70+
/>
71+
<FlagButton
72+
label={"A"}
73+
isSelected={selectedSemesters.includes("A")}
74+
onClick={() => onClick("A")}
75+
className="col-span-2"
76+
/>
77+
</div>
78+
);
79+
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* 全てのフィルターを表示するコンポーネント
3+
*/
4+
5+
"use client";
6+
import { useState } from "react";
7+
import { ClassType, Evaluation, Semester } from "@/app/type";
8+
import { SemestersCheckbox } from "./FilterComponents/Semester";
9+
import { FilterCard } from "./UI/FilterCard";
10+
11+
/**
12+
* フィルタの型定義
13+
*/
14+
type Filter = {
15+
isFreewordForSyllabusDetail?: boolean; // フリーワード検索
16+
semesters?: Semester[]; // セメスター
17+
evaluation_included?: Evaluation[]; // 含めたい評価方法
18+
evaluation_excluded?: Evaluation[]; // 除外したい評価方法
19+
classTypes?: ClassType[]; // 種別
20+
showRegistered?: boolean; // 履修登録済みの授業を表示する
21+
showNotRegistered?: boolean; // 未履修の授業を表示する
22+
};
23+
24+
/**
25+
* フィルタUI
26+
* @returns フィルタUI
27+
*/
28+
export const FilterUI: React.FC = () => {
29+
// 現在のフィルター
30+
const [filter, setFilter] = useState<Filter>({});
31+
32+
return (
33+
<div className="flex gap-8 flex-wrap">
34+
<FilterCard title={"セメスター"}>
35+
<SemestersCheckbox
36+
selectedSemesters={filter.semesters}
37+
setSelectedSemesters={(semesters: Semester[]) =>
38+
setFilter({ ...filter, semesters })
39+
}
40+
/>
41+
</FilterCard>
42+
</div>
43+
);
44+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* FilterUIのサンプルページ
3+
*/
4+
5+
import { FilterUI } from "../FilterUI";
6+
7+
const FilterUISample: React.FC = () => {
8+
return <FilterUI />;
9+
};
10+
11+
export default FilterUISample;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* フィルターの内容とタイトルをセットにするコンポーネント
3+
*/
4+
5+
import React, { ReactNode } from "react";
6+
7+
/**
8+
* フィルターカードのプロパティ
9+
*/
10+
export interface FilterCardProps {
11+
/** タイトル */
12+
title: string;
13+
14+
/** フィルター */
15+
children: ReactNode;
16+
}
17+
18+
/**
19+
* フィルターの内容とタイトルをセットにするコンポーネント
20+
* @param param0 プロパティ
21+
* @param param0.title フィルターのタイトル
22+
* @param param0.children フィルターコンポーネント
23+
* @returns コンポーネント
24+
*/
25+
export const FilterCard: React.FC<FilterCardProps> = ({ title, children }) => {
26+
return (
27+
<div className="gap-8 flex-wrap">
28+
<div className="text-2xl m-4">{title}</div>
29+
{children}
30+
</div>
31+
);
32+
};
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* 選択状態を示すボタン。
3+
* (ボタンの背景色を変更することで選択状態を示す。)
4+
* セメスター選択ボタンや、種別選択ボタンで使用。
5+
*/
6+
7+
import React from "react";
8+
9+
/**
10+
* 選択状態を示すボタンのプロパティ
11+
*/
12+
interface FlagButtonProp {
13+
/**
14+
* ボタンのラベル
15+
*/
16+
label: string;
17+
/**
18+
* 選択状態かどうか
19+
*/
20+
isSelected: boolean;
21+
/**
22+
* ボタンがクリックされたときの処理
23+
*/
24+
onClick: () => void;
25+
26+
/**
27+
* ボタンのスタイル
28+
*/
29+
className?: string;
30+
}
31+
32+
/**
33+
* 選択状態を示すボタンのコンポーネント
34+
* @param prop 選択状態を示すボタンのプロパティ
35+
* @returns 選択状態を示すボタンのコンポーネント
36+
*/
37+
export const FlagButton: React.FC<FlagButtonProp> = (prop: FlagButtonProp) => {
38+
const className = prop.className ?? "";
39+
return (
40+
<button
41+
className={
42+
`${
43+
prop.isSelected ? "bg-primary/30" : "bg-surface"
44+
} text-text-default px-4 py-2 rounded-full outline-2 outline-primary/30 outline` +
45+
" " +
46+
className
47+
}
48+
onClick={prop.onClick}
49+
>
50+
{prop.label}
51+
</button>
52+
);
53+
};

src/app/type.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,29 @@ export const dayMapping: { [key in Day]: string } = {
5959
fri: "金",
6060
sat: "土",
6161
};
62+
63+
/**
64+
* セメスターを表現する型
65+
*/
66+
export type Semester = "S" | "S1" | "S2" | "A" | "A1" | "A2";
67+
68+
/**
69+
* 評価方法を表現する型
70+
*/
71+
export type Evaluation = "試験" | "レポート" | "出席" | "平常";
72+
73+
/**
74+
* セメスターを表現する型
75+
*/
76+
export type ClassType =
77+
| "基礎"
78+
| "要求"
79+
| "主題"
80+
| "展開"
81+
| "L"
82+
| "A"
83+
| "B"
84+
| "C"
85+
| "D"
86+
| "E"
87+
| "F";

0 commit comments

Comments
 (0)