diff --git a/.gitignore b/.gitignore
index 1d2246a..78b6ee7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,4 +23,4 @@ dist-ssr
*.sln
*.sw?
-firebase.config.ts
\ No newline at end of file
+src/plugins/firebase.config.ts
\ No newline at end of file
diff --git a/src/App.tsx b/src/App.tsx
index de074b8..d1c486b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,13 +1,13 @@
import { Notifications } from "@mantine/notifications"
import { BrowserRouter as Router } from "react-router-dom"
-import DetermineLayout from './determineLayout.tsx'
+import Layout from './layouts'
export default function App() {
return (
<>
-
+
>
)
diff --git a/src/axios.ts b/src/axios.ts
index ab13acd..3ad585b 100644
--- a/src/axios.ts
+++ b/src/axios.ts
@@ -1,17 +1,15 @@
import _axios from "axios"
// import useUserStore from "./store/user"
-import { getAuth, getIdToken, onAuthStateChanged } from "firebase/auth"
+import { Auth, User, getAuth, getIdToken, onAuthStateChanged } from "firebase/auth"
-// const auth = getAuth()
-// let idToken = ''
-// onAuthStateChanged(auth, async (user) => {
-// if (!user) return;
-
-// idToken = await getIdToken(user, true)
-// })
-
-// const idToken = use
-// const idToken = useUserStore.getState().idToken
+const checkFirebaseAuth = (auth: Auth) => {
+ return new Promise((resolve) => {
+ onAuthStateChanged(auth, (user) => {
+ // user オブジェクトを resolve
+ resolve(user);
+ });
+ });
+}
const axios = _axios.create({
baseURL: 'http://localhost:9000/v2',
@@ -23,18 +21,16 @@ const axios = _axios.create({
responseType: 'json',
})
-axios.interceptors.request.use((request) => {
+axios.interceptors.request.use(async (request) => {
//リクエスト前に毎回idTokenを取得する
const auth = getAuth()
- onAuthStateChanged(auth, async (user) => {
- if (!user) return;
-
- const idToken = await getIdToken(user, true)
+ const user = await checkFirebaseAuth(auth)
- if (!idToken) return;
+ if (!user) return request;
- request.headers.Authorization = idToken
- })
+ const idToken = await getIdToken(user, true)
+ request.headers.Authorization = idToken
+
return request
},(error) => {
// リクエスト エラーの処理
diff --git a/src/components/FilteringLevel.tsx b/src/components/FilteringLevel.tsx
new file mode 100644
index 0000000..487f0ef
--- /dev/null
+++ b/src/components/FilteringLevel.tsx
@@ -0,0 +1,43 @@
+import useSWR from "swr";
+import { fetcher } from "../fetchers";
+import { Checkbox, DefaultProps, Group } from "@mantine/core";
+
+interface FilteringLevelProps extends DefaultProps {
+ value: string[] | undefined,
+ onChange: React.Dispatch>,
+}
+
+export interface Level{
+ id: number,
+ name: string,
+ color: string,
+}
+
+export default function FilteringLevel({
+ value,
+ onChange,
+ ...others
+}: FilteringLevelProps) {
+ const { data: levels } = useSWR('/levels', fetcher)
+
+ return (
+
+
+ {levels?.map(level =>
+
+ )}
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/FilteringWord.tsx b/src/components/FilteringWord.tsx
new file mode 100644
index 0000000..7a063f9
--- /dev/null
+++ b/src/components/FilteringWord.tsx
@@ -0,0 +1,51 @@
+import { DefaultProps, Group, Radio, TextInput } from "@mantine/core"
+import { formInputProps } from "../hooks"
+
+export type optionProps = {
+ value: string,
+ onChange: (value: string) => void
+}
+
+interface FilteringWordProps extends DefaultProps {
+ wordInputProps: formInputProps,
+ wordSearchOption: optionProps,
+}
+
+export default function FilteringWord({
+ wordInputProps,
+ wordSearchOption,
+ className,
+ ...others
+}: FilteringWordProps) {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/src/components/FilteringWorkbook.tsx b/src/components/FilteringWorkbook.tsx
new file mode 100644
index 0000000..c2e561a
--- /dev/null
+++ b/src/components/FilteringWorkbook.tsx
@@ -0,0 +1,57 @@
+import React, { forwardRef } from "react";
+import useSWR from "swr";
+import { fetcher } from "../fetchers";
+import { Badge, DefaultProps, Group, MultiSelect } from "@mantine/core";
+
+interface WorkbookProps extends React.ComponentPropsWithoutRef<'div'> {
+ id: string,
+ label: string,
+ color: string,
+}
+
+export interface Workbook {
+ id: number,
+ label: string,
+ color: string,
+}
+
+interface FilteringWorkbookProps extends DefaultProps {
+ value: string[] | undefined,
+ onChange: React.Dispatch>
+}
+
+export default function FilteringWorkbook({
+ value,
+ onChange,
+ ...others
+ }: FilteringWorkbookProps ) {
+ const { data: workbooks } = useSWR('/workbooks/color', fetcher)
+
+ const data = workbooks ? workbooks.map(({id, label, ...others}) => ({...others, value: String(id), key: id, label})) : []
+
+ const Item = forwardRef(
+ ({ id, label, color, ...others}: WorkbookProps, ref) => (
+
+
+ {label}
+
+
+ ))
+
+ return (
+ !selected && (item.label?.includes(value) || false)}
+ value={value}
+ onChange={onChange}
+ {...others}
+ />
+ )
+}
\ No newline at end of file
diff --git a/src/components/QuizCard.tsx b/src/components/QuizCard.tsx
index 5df6490..9102ae9 100644
--- a/src/components/QuizCard.tsx
+++ b/src/components/QuizCard.tsx
@@ -1,7 +1,16 @@
import { Badge, Card, DefaultProps, Flex, Group, MantineNumberSize, Selectors, Text, } from "@mantine/core";
import QuizMylistButton from "./QuizMylistButton";
import QuizFavoriteButton from "./QuizFavoriteButton";
-import useStyles, { QuizCardStylesParams } from "./QuizCard.styles";
+import useStyles, { QuizCardStylesParams } from "./styles/QuizCard.styles";
+
+export interface Quiz {
+ id: number,
+ question: string,
+ answer: string,
+ workbook: string,
+ level: string,
+ date: string,
+}
// このtypeは,useStyleに定義されたすべてのselectorsを含む結合が存在する.
// ここではroot | title | descriptionである.
@@ -10,8 +19,7 @@ type QuizCardStylesNames = Selectors
interface QuizCardProps extends DefaultProps {
margin?: MantineNumberSize,
index: number,
- question: string,
- answer: string,
+ quiz: Quiz,
}
export default function QuizCard({
@@ -20,10 +28,8 @@ export default function QuizCard({
unstyled,
className,
margin,
- index = 1,
- question = "",
- answer="",
-
+ index,
+ quiz,
}: QuizCardProps) {
const { classes, cx } = useStyles(
{ margin },
@@ -36,16 +42,21 @@ export default function QuizCard({
No.{index}
- {question}
+ {quiz.question}
- {answer}
+ {quiz.answer}
- abc2014
+
+ {quiz.workbook}({quiz.date.slice(0, 4)})
+
)
diff --git a/src/components/QuizCardList.tsx b/src/components/QuizCardList.tsx
index 6ce0321..f577d8d 100644
--- a/src/components/QuizCardList.tsx
+++ b/src/components/QuizCardList.tsx
@@ -1,16 +1,9 @@
import QuizCard from "./QuizCard"
-import { useEffect } from "react"
import useQuizzesStore from "../store/quiz"
import { Center, Loader } from "@mantine/core"
-// import { useFetch } from "../hooks"
export default function QuizCardList() {
const quizzes = useQuizzesStore(state => state.quizzes)
- const getQuizzes = useQuizzesStore(state => state.getQuiz)
-
- useEffect(() => {
- getQuizzes()
- }, [])
if (!quizzes) {
return (
@@ -22,12 +15,11 @@ export default function QuizCardList() {
return (
<>
- {quizzes?.map(({question, answer}, idx) => (
+ {quizzes?.map((quiz, idx) => (
({
root: {
marginBottom: theme.spacing.xs
diff --git a/src/components/QuizFilteringModal.tsx b/src/components/QuizFilteringModal.tsx
new file mode 100644
index 0000000..c68538d
--- /dev/null
+++ b/src/components/QuizFilteringModal.tsx
@@ -0,0 +1,78 @@
+import { Button, Group, Modal } from "@mantine/core"
+import { useDisclosure } from "@mantine/hooks"
+import { useState } from "react"
+import FilteringWorkbook from "./FilteringWorkbook"
+import FilteringLevel from "./FilteringLevel"
+import { useInput, useIsMobile } from "../hooks"
+import FilteringWord from "./FilteringWord"
+import { IconFilter, IconSearch } from "@tabler/icons-react"
+import useQuizzesStore, { QuizRequestParams } from "../store/quiz"
+
+export type Level = {
+ id: number,
+ name: string,
+ color: string,
+}
+
+export default function QuizFilteringModal() {
+ const [ opened, { open, close } ] = useDisclosure(true)
+ const [ selectedWorkbook, setSelectedWorkbook ] = useState([])
+ const [ selectedLevel, setSelectedLevel ] = useState([])
+ const [ keywordProps ] = useInput('')
+ const [ keywordOption, setkeywordOption ] = useState('1')
+ const isMobile = useIsMobile()
+ const getQuiz = useQuizzesStore(state => state.getQuiz)
+
+ const filtering = async () => {
+ const params: QuizRequestParams = {
+ workbook: selectedWorkbook,
+ level: selectedLevel,
+ keyword: keywordProps.value,
+ keywordOption: keywordOption
+ }
+ close()
+ await getQuiz(params)
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/src/components/QuizCard.styles.ts b/src/components/styles/QuizCard.styles.ts
similarity index 100%
rename from src/components/QuizCard.styles.ts
rename to src/components/styles/QuizCard.styles.ts
diff --git a/src/hooks.ts b/src/hooks.ts
index cb3b28e..71778ca 100644
--- a/src/hooks.ts
+++ b/src/hooks.ts
@@ -1,16 +1,21 @@
import { useEffect, useState } from "react"
import useUserStore from "./store/user"
+import { useMediaQuery } from "@mantine/hooks"
+
+export interface formInputProps {
+ value: string,
+ onChange: (e: React.ChangeEvent) => void
+}
+
+export type formInputReset = () => void
export const useInput = (
- initialValue: number | string,
+ initialValue: string,
): [
- {
- value: number | string,
- onChange: (e: React.ChangeEvent) => void
- },
- () => void,
+ formInputProps,
+ formInputReset
] => {
- const [ value, setValue ] = useState(initialValue)
+ const [ value, setValue ] = useState(initialValue)
const props = {
value,
@@ -23,6 +28,11 @@ export const useInput = (
]
}
+export const useIsMobile = () => {
+ const matches = useMediaQuery('(min-width: 48em)');
+ return !matches
+}
+
export const useFetch = (
url: string,
init?: RequestInit
diff --git a/src/layouts/login.tsx b/src/layouts/draft.tsx
similarity index 100%
rename from src/layouts/login.tsx
rename to src/layouts/draft.tsx
diff --git a/src/determineLayout.tsx b/src/layouts/index.tsx
similarity index 58%
rename from src/determineLayout.tsx
rename to src/layouts/index.tsx
index df8b292..8e5f07f 100644
--- a/src/determineLayout.tsx
+++ b/src/layouts/index.tsx
@@ -1,21 +1,22 @@
-import { Route, Routes, useLocation } from "react-router-dom"
-import Home from "./routers/home"
-import Login from "./routers/login"
-import DefaultLayout from "./layouts/default"
-import LoginLayout from "./layouts/login"
-
-export default function Root() {
- const location = useLocation()
- const requiredLogin = location.pathname !== '/login'
-
- const Layout = requiredLogin ? DefaultLayout : LoginLayout
-
- return (
-
-
- }/>
- }/>
-
-
- )
+import { Route, Routes, useLocation } from "react-router-dom"
+import Home from "../pages/home"
+import Login from "../pages/login"
+import DefaultLayout from "./default"
+import DraftLayout from "./draft"
+
+export default function Root() {
+ const location = useLocation()
+ const requiredLogin = location.pathname !== '/login'
+
+ const Layout = requiredLogin ? DefaultLayout : DraftLayout
+ //const Layout = DefaultLayout
+
+ return (
+
+
+ }/>
+ }/>
+
+
+ )
}
\ No newline at end of file
diff --git a/src/routers/home.tsx b/src/pages/home.tsx
similarity index 57%
rename from src/routers/home.tsx
rename to src/pages/home.tsx
index dea22ba..25c03ae 100644
--- a/src/routers/home.tsx
+++ b/src/pages/home.tsx
@@ -1,10 +1,10 @@
import QuizCardList from '../components/QuizCardList'
-import LogoutButtom from '../components/LogoutButton'
+import QuizFilteringModal from '../components/QuizFilteringModal'
export default function Home() {
return (
<>
-
+
>
)
diff --git a/src/routers/login.tsx b/src/pages/login.tsx
similarity index 93%
rename from src/routers/login.tsx
rename to src/pages/login.tsx
index 3a8ee42..4a8c965 100644
--- a/src/routers/login.tsx
+++ b/src/pages/login.tsx
@@ -1,5 +1,5 @@
import { useNavigate } from "react-router-dom"
-import { auth } from "../firebase"
+import { auth } from "../plugins/firebase"
import { signInWithEmailAndPassword } from "firebase/auth"
import { Button, Center, Grid, Paper, PasswordInput, TextInput } from "@mantine/core"
import { useInput } from "../hooks"
diff --git a/src/firebase.ts b/src/plugins/firebase.ts
similarity index 100%
rename from src/firebase.ts
rename to src/plugins/firebase.ts
diff --git a/src/store/quiz.ts b/src/store/quiz.ts
index e06728d..40f7780 100644
--- a/src/store/quiz.ts
+++ b/src/store/quiz.ts
@@ -1,6 +1,5 @@
import { create } from 'zustand'
import axios from '../axios'
-import { AxiosRequestConfig } from 'axios'
export type Quiz = {
id: number,
@@ -8,35 +7,36 @@ export type Quiz = {
answer: string,
workbook: string,
level: string,
- date: Date,
+ date: string,
total: number,
right: number,
isFavorite: boolean,
registerdMylist: number[],
}
-export type QuizRequestParams = {
- page: number,
- maxView: number,
- seed: number,
- workbooks: number[],
- levels: number[],
- queWord: string,
- ansWord: string,
- start?: string,
- end?: string,
- judgement?: string,
+export interface QuizRequestParams {
+ page?: number,
+ maxView?: number,
+ seed?: number,
+ workbook?: string[],
+ level?: string[],
+ keyword?: string,
+ keywordOption?: string,
+ since?: string,
+ until?: string,
+ judgement?: number,
}
export type QuizState = {
quizzes: Quiz[] | null,
- getQuiz: (params?: AxiosRequestConfig) => void
+ getQuiz: (params?: QuizRequestParams) => void
}
const useQuizzesStore = create((set) => ({
quizzes: null,
- getQuiz: async (params) => {
- const quizzes = await axios.get('/quizzes/8', params).then(res => res.data)
+ getQuiz: async (params?: QuizRequestParams) => {
+ console.log(params)
+ const quizzes = await axios.get('/quizzes/8', { params }).then(res => res.data)
set({ quizzes })
}
}))
diff --git a/src/store/workbook.ts b/src/store/workbook.ts
new file mode 100644
index 0000000..17b27ef
--- /dev/null
+++ b/src/store/workbook.ts
@@ -0,0 +1,23 @@
+import { create } from "zustand"
+import axios from "../axios"
+
+export type Workbook = {
+ id: number,
+ label: string,
+ color: string,
+}
+
+export type WorkbookState = {
+ workbooks: Workbook[] | null,
+ getWorkbook: () => void
+}
+
+const useWorkbookStore = create((set) => ({
+ workbooks: null,
+ getWorkbook: async () => {
+ const workbooks = await axios('/workbooks/color').then(res => res.data)
+ set({ workbooks })
+ }
+}))
+
+export default useWorkbookStore
\ No newline at end of file
diff --git a/vite.config.ts b/vite.config.ts
index 5a33944..3bdb42a 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -3,5 +3,10 @@ import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
+ server: {
+ proxy: {
+ "^/api/.*": "http://localhost:4000",
+ },
+ },
plugins: [react()],
})