diff --git a/README.md b/README.md index 58beeac..13dacaf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,38 @@ +# Cloning the Repository + +To clone this repository along with its submodules, follow the instructions below. These steps will ensure that you have a complete copy of the project, including [กรธ.60 - Data Query](https://github.com/iampz/c60-data-query.git) + +### Steps to Clone + +1. **Clone the Repository** + + Open your terminal or command prompt and run the following command: + + ``` + git clone --recurse-submodules https://github.com/kaogeek/cons60-web + ``` + + This command clones the repository and all its submodules. + +1. **Initialize and Update Submodules** + + If the repository was cloned without using `--recurse-submodules`, you need to run the following commands to initialize and update the submodules: + + ``` + git submodule update --init --recursive + ``` + +This command initializes your local configuration file for submodules and updates the submodules. + +### Troubleshooting + +If you encounter any issues with submodules, such as broken links or missing files, you can try re-syncing and updating the submodules: + +``` +git submodule sync +git submodule update --init --recursive +``` + # Getting Started with Create React App This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). diff --git a/src/App.js b/src/App.js index 23faeed..07bba5a 100644 --- a/src/App.js +++ b/src/App.js @@ -3,16 +3,22 @@ import { Routes, Route } from "react-router-dom"; import Navbar from "./components/Navbar"; import Home from "./pages/Home"; import About from "./pages/About"; +import Search from "./pages/Search"; import Chapter from "./pages/Chapter"; +import Discussionist from "./pages/Discussionist"; +import ScrollToTop from "./components/ScrollToTop"; export default function App() { return ( -
+
+ } /> } /> + } /> } /> + } />
) diff --git a/src/c60-data-query b/src/c60-data-query index e88bc2a..47aa3b6 160000 --- a/src/c60-data-query +++ b/src/c60-data-query @@ -1 +1 @@ -Subproject commit e88bc2ad6a61bbd754aab2405f96946402ce64cd +Subproject commit 47aa3b6dadfb8d616b513f477f6915bc700d3fd0 diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index dfdc335..1aabde0 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -1,76 +1,136 @@ -import React from "react"; import Logo from "./Logo"; import HamburgerSVG from "./HamburgerSVG"; import CloseBtnSVG from "./CloseBtnSVG"; import { Link } from "react-router-dom"; +import { useLocation } from 'react-router-dom'; +import { Icon } from "@iconify/react"; +import React, { useEffect, useRef } from "react"; + function Navbar() { const [showMenu, setShowMenu] = React.useState(false); + const location = useLocation(); + const searchInputRef = useRef(null); + + useEffect(() => { + // Automatically focus the search input when on the search page + if (location.pathname === '/search') { + searchInputRef.current?.focus(); + } + }, [location.pathname]); // Dependency array to re-run effect when pathname changes + return (
- - - + + + {location.pathname === '/search' && ( +
+ + + + + + +
+ )} + + {location.pathname === '/search' && ( +
+ {/* Replace this with your actual search bar component */} + +
+ +
+ +
+ +
+ + )} + + {location.pathname === '/search' && ( +
+
+ )} + + {location.pathname !== '/search' && ( +
+ + + +
+ )} + {/* Desktop Menu */} -
- - ภาพรวม - - - เกี่ยวกับโครงการ - -
- {/* Mobile Menu */} -
- {/* Hamburger menu icon for mobile */} - {!showMenu ? ( - - ) : ( - - )} - - {showMenu && ( -
- {/* Mobile menu items */} -
-
- - ภาพรวม - -
-
- - เกี่ยวกับโครงการ - + {location.pathname !== '/search' && ( +
+
+ + ภาพรวม + + + เกี่ยวกับโครงการ + +
+ {/* Mobile Menu */} +
+ {/* Hamburger menu icon for mobile */} + {!showMenu ? ( + + ) : ( + + )} + + {showMenu && ( +
+ {/* Mobile menu items */} +
+
+ + ภาพรวม + +
+
+ + เกี่ยวกับโครงการ + +
+
-
+ )}
- )} -
+
+ )}
); diff --git a/src/components/Overview/ByDiscussionist.jsx b/src/components/Overview/ByDiscussionist.jsx index 05b5924..eb36e5e 100644 --- a/src/components/Overview/ByDiscussionist.jsx +++ b/src/components/Overview/ByDiscussionist.jsx @@ -140,7 +140,7 @@ function ByDiscussionist() {
{result.map(([discussionist, chapterCountMap]) => ( diff --git a/src/components/ScrollToTop.jsx b/src/components/ScrollToTop.jsx new file mode 100644 index 0000000..8b76e36 --- /dev/null +++ b/src/components/ScrollToTop.jsx @@ -0,0 +1,12 @@ +import { useEffect } from "react"; +import { useLocation } from "react-router-dom"; + +export default function ScrollToTop() { + const { pathname } = useLocation(); + + useEffect(() => { + window.scrollTo(0, 0); + }, [pathname]); + + return null; +} \ No newline at end of file diff --git a/src/pages/Discussionist.jsx b/src/pages/Discussionist.jsx new file mode 100644 index 0000000..b90a86e --- /dev/null +++ b/src/pages/Discussionist.jsx @@ -0,0 +1,195 @@ +import { Link, useParams } from "react-router-dom"; +import React, { useState, useEffect, useCallback, useRef } from "react"; +import { useMediaQuery } from "react-responsive"; +import { Icon } from "@iconify/react"; + +import ChapterMobilePillButton from "../components/SelectChapters/ChapterMobilePillButton"; +import SelectChaptersMobile from "../components/SelectChapters/SelectChaptersMobile"; +import SelectChapters from "../components/SelectChapters/SelectChapters"; +import ListItem from "../components/ListItem"; +import chapterColorCode from "../constants/chapterColorCode.js"; +import SortBy from "../components/SortBy"; +import ProfileImages from "../components/ProfileImages"; + +import createDataObject from "../c60-data-query/data-object.js"; +import data from "../c60-data-query/data.js"; +import { chapterIdToName, chapterNameToId } from "../constants/chapters.js"; + +export default function Discussionist() { + const { name } = useParams(); + + const [sort, setSort] = useState(0); + const [selectedChapters, setSelectedChapters] = useState([]); + const [result, setResult] = useState([]); + + // Mobile + const isMobile = useMediaQuery({ query: `(max-width: 768px)` }); + const [showSelectChapters, setShowSelectChapters] = useState(false); + + const resultDivRef = useRef(null); + + const handleSelectChapters = (newSelected) => { + setSelectedChapters(newSelected); + }; + + const handleChaptersModalClose = () => { + setShowSelectChapters(false); + if (resultDivRef && resultDivRef.current) { + resultDivRef.current.scrollIntoView(); + } + }; + + const handleRemoveChapter = (chapter) => { + setSelectedChapters((prev) => prev.filter((s) => s !== chapter)); + }; + + const queryData = useCallback(() => { + const chapterIds = selectedChapters.map((chapter) => ({ + หมวด: chapterNameToId[chapter], + })); + + const dataObject = + selectedChapters.length >= 1 + ? createDataObject(data) + .multiFilter(chapterIds, []) + .filterArray("ผู้อภิปราย", name) + : createDataObject(data).filterArray("ผู้อภิปราย", name); + + const newResult = dataObject.data.reduce((acc, row) => { + const chapterName = chapterIdToName[row["หมวด"]]; + const SectionNumber = row["มาตรา"]; + + if (!acc[SectionNumber]) { + acc[SectionNumber] = {}; + acc[SectionNumber]["total"] = 1; + } else { + acc[SectionNumber]["total"] += 1; + } + acc[SectionNumber]["chapterName"] = chapterName; + return acc; + }, {}); + + // Convert to array for sorting later + // [name, {chapterName, total}] + return Object.entries(newResult); + }, [name, selectedChapters]); + + const sortResult = useCallback( + (result) => { + return result.sort((a, b) => + sort === 0 ? b[1].total - a[1].total : a[1].total - b[1].total + ); + }, + [sort] + ); + + useEffect(() => { + const editRecord = queryData(); + const sortedEditRecord = sortResult(editRecord); + setResult(sortedEditRecord); + }, [queryData, sortResult]); + + return ( + <> +
+
+ + + + + + +

{name}

+
+
+
+
+ {isMobile ? null : ( + + )} +
+
+ {isMobile ? ( +
+ +
+ {selectedChapters.map((chapter) => ( + + ))} +
+
+ ) : ( + <> + {selectedChapters.length >= 1 ? ( +
+ ได้เลือก {selectedChapters.length} จากทั้งหมด +
+ ) : ( +
ทุกหมวด
+ )} + + )} + +
+
+ {result.map(([Section, { chapterName, total }]) => ( + + + + ))} +
+
+
+
+ {showSelectChapters && isMobile ? ( + + ) : null} + + ); +} diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 31160b6..e85339d 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,5 +1,6 @@ import React, { useState } from "react"; import { Icon } from "@iconify/react"; +import { Link } from "react-router-dom"; import "../styles/Home.css"; import ByChapter from "../components/Overview/ByChapter"; @@ -32,6 +33,7 @@ export default function Home() { ออกมาเพื่อใคร หาคำตอบไปด้วยกัน
+
@@ -46,6 +48,8 @@ export default function Home() {
+ +
diff --git a/src/pages/Search.jsx b/src/pages/Search.jsx new file mode 100644 index 0000000..5e0546e --- /dev/null +++ b/src/pages/Search.jsx @@ -0,0 +1,18 @@ +import React from "react"; +import "../components/ProfileImages.jsx"; +export default function Search() { + return ( +
+
+
+

+ ค้นหาตามมาตรา +

+

+ ค้นหาตามผู้อภิปราย +

+
+
+
+ ); +}