refactor(nav): Implement React Router for navigation

- Replace button-based navigation with React Router Links in Navbar
- Add BrowserRouter, Routes, and Route components in App.js
- Update Navbar to determine active tab based on current route
- Remove setActiveTab prop from Navbar component
- Update RegexPage, FormatPage, and SettingsPage imports in App.js
- Adjust Navbar propTypes to remove activeTab and setActiveTab
This commit is contained in:
santiagosayshey
2024-08-24 00:35:16 +09:30
committed by Sam Chau
parent fd9d23a828
commit 330c162b0e
7 changed files with 457 additions and 109 deletions

View File

@@ -1,18 +1,18 @@
import { useState, useEffect } from 'react';
import FormatCard from './FormatCard';
import FormatModal from './FormatModal';
import AddNewCard from '../ui/AddNewCard';
import { getFormats } from '../../api/api';
import FilterMenu from '../ui/FilterMenu';
import SortMenu from '../ui/SortMenu';
import { useState, useEffect } from "react";
import FormatCard from "./FormatCard";
import FormatModal from "./FormatModal";
import AddNewCard from "../ui/AddNewCard";
import { getFormats } from "../../api/api";
import FilterMenu from "../ui/FilterMenu";
import SortMenu from "../ui/SortMenu";
function FormatManager() {
function FormatPage() {
const [formats, setFormats] = useState([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedFormat, setSelectedFormat] = useState(null);
const [sortBy, setSortBy] = useState('title');
const [filterType, setFilterType] = useState('none');
const [filterValue, setFilterValue] = useState('');
const [sortBy, setSortBy] = useState("title");
const [filterType, setFilterType] = useState("none");
const [filterValue, setFilterValue] = useState("");
const [allTags, setAllTags] = useState([]);
useEffect(() => {
@@ -23,10 +23,12 @@ function FormatManager() {
try {
const fetchedFormats = await getFormats();
setFormats(fetchedFormats);
const tags = [...new Set(fetchedFormats.flatMap(format => format.tags || []))];
const tags = [
...new Set(fetchedFormats.flatMap((format) => format.tags || [])),
];
setAllTags(tags);
} catch (error) {
console.error('Error fetching formats:', error);
console.error("Error fetching formats:", error);
}
};
@@ -46,10 +48,10 @@ function FormatManager() {
};
const handleCloneFormat = (format) => {
const clonedFormat = {
...format,
const clonedFormat = {
...format,
id: 0, // Ensure the ID is 0 for a new entry
name: `${format.name} [COPY]`
name: `${format.name} [COPY]`,
};
setSelectedFormat(clonedFormat); // Set cloned format
setIsModalOpen(true); // Open modal in Add mode
@@ -60,11 +62,11 @@ function FormatManager() {
};
const sortedAndFilteredFormats = formats
.filter(format => {
if (filterType === 'tag') {
.filter((format) => {
if (filterType === "tag") {
return format.tags && format.tags.includes(filterValue);
}
if (filterType === 'date') {
if (filterType === "date") {
const formatDate = new Date(format.date_modified);
const filterDate = new Date(filterValue);
return formatDate.toDateString() === filterDate.toDateString();
@@ -72,9 +74,11 @@ function FormatManager() {
return true;
})
.sort((a, b) => {
if (sortBy === 'title') return a.name.localeCompare(b.name);
if (sortBy === 'dateCreated') return new Date(b.date_created) - new Date(a.date_created);
if (sortBy === 'dateModified') return new Date(b.date_modified) - new Date(a.date_modified);
if (sortBy === "title") return a.name.localeCompare(b.name);
if (sortBy === "dateCreated")
return new Date(b.date_created) - new Date(a.date_created);
if (sortBy === "dateModified")
return new Date(b.date_modified) - new Date(a.date_modified);
return 0;
});
@@ -93,12 +97,12 @@ function FormatManager() {
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 mb-4">
{sortedAndFilteredFormats.map((format) => (
<FormatCard
key={format.id}
format={format}
<FormatCard
key={format.id}
format={format}
onEdit={() => handleOpenModal(format)}
onClone={handleCloneFormat} // Pass the clone handler
showDate={sortBy !== 'title'}
showDate={sortBy !== "title"}
formatDate={formatDate}
/>
))}
@@ -115,4 +119,4 @@ function FormatManager() {
);
}
export default FormatManager;
export default FormatPage;

View File

@@ -1,18 +1,18 @@
import { useState, useEffect } from 'react';
import RegexCard from './RegexCard';
import RegexModal from './RegexModal';
import AddNewCard from '../ui/AddNewCard';
import { getRegexes } from '../../api/api';
import FilterMenu from '../ui/FilterMenu';
import SortMenu from '../ui/SortMenu';
import { useState, useEffect } from "react";
import RegexCard from "./RegexCard";
import RegexModal from "./RegexModal";
import AddNewCard from "../ui/AddNewCard";
import { getRegexes } from "../../api/api";
import FilterMenu from "../ui/FilterMenu";
import SortMenu from "../ui/SortMenu";
function RegexManager() {
function RegexPage() {
const [regexes, setRegexes] = useState([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedRegex, setSelectedRegex] = useState(null);
const [sortBy, setSortBy] = useState('title');
const [filterType, setFilterType] = useState('none');
const [filterValue, setFilterValue] = useState('');
const [sortBy, setSortBy] = useState("title");
const [filterType, setFilterType] = useState("none");
const [filterValue, setFilterValue] = useState("");
const [allTags, setAllTags] = useState([]);
useEffect(() => {
@@ -23,10 +23,12 @@ function RegexManager() {
try {
const fetchedRegexes = await getRegexes();
setRegexes(fetchedRegexes);
const tags = [...new Set(fetchedRegexes.flatMap(regex => regex.tags || []))];
const tags = [
...new Set(fetchedRegexes.flatMap((regex) => regex.tags || [])),
];
setAllTags(tags);
} catch (error) {
console.error('Error fetching regexes:', error);
console.error("Error fetching regexes:", error);
}
};
@@ -46,11 +48,11 @@ function RegexManager() {
};
const handleCloneRegex = (regex) => {
const clonedRegex = {
...regex,
const clonedRegex = {
...regex,
id: 0, // Ensure the ID is 0 for a new entry
name: `${regex.name} [COPY]`,
regex101Link: '' // Remove the regex101 link
name: `${regex.name} [COPY]`,
regex101Link: "", // Remove the regex101 link
};
setSelectedRegex(clonedRegex); // Set cloned regex
setIsModalOpen(true); // Open modal in Add mode
@@ -61,11 +63,11 @@ function RegexManager() {
};
const sortedAndFilteredRegexes = regexes
.filter(regex => {
if (filterType === 'tag') {
.filter((regex) => {
if (filterType === "tag") {
return regex.tags && regex.tags.includes(filterValue);
}
if (filterType === 'date') {
if (filterType === "date") {
const regexDate = new Date(regex.date_modified);
const filterDate = new Date(filterValue);
return regexDate.toDateString() === filterDate.toDateString();
@@ -73,9 +75,11 @@ function RegexManager() {
return true;
})
.sort((a, b) => {
if (sortBy === 'title') return a.name.localeCompare(b.name);
if (sortBy === 'dateCreated') return new Date(b.date_created) - new Date(a.date_created);
if (sortBy === 'dateModified') return new Date(b.date_modified) - new Date(a.date_modified);
if (sortBy === "title") return a.name.localeCompare(b.name);
if (sortBy === "dateCreated")
return new Date(b.date_created) - new Date(a.date_created);
if (sortBy === "dateModified")
return new Date(b.date_modified) - new Date(a.date_modified);
return 0;
});
@@ -99,7 +103,7 @@ function RegexManager() {
regex={regex}
onEdit={() => handleOpenModal(regex)}
onClone={handleCloneRegex} // Pass the clone handler
showDate={sortBy !== 'title'}
showDate={sortBy !== "title"}
formatDate={formatDate}
/>
))}
@@ -116,4 +120,4 @@ function RegexManager() {
);
}
export default RegexManager;
export default RegexPage;

View File

@@ -33,7 +33,7 @@ import CommitSection from "./CommitSection";
import Tooltip from "../ui/Tooltip";
import DiffModal from "./DiffModal";
const SettingsManager = () => {
const SettingsPage = () => {
const [settings, setSettings] = useState(null);
const [status, setStatus] = useState(null);
const [showModal, setShowModal] = useState(false);
@@ -637,4 +637,4 @@ const SettingsManager = () => {
);
};
export default SettingsManager;
export default SettingsPage;

View File

@@ -1,16 +1,30 @@
import PropTypes from 'prop-types';
import { useState, useEffect, useRef } from 'react';
import PropTypes from "prop-types";
import { useState, useEffect, useRef } from "react";
import { Link, useLocation } from "react-router-dom";
function ToggleSwitch({ checked, onChange }) {
return (
<label className="flex items-center cursor-pointer">
<div className="relative">
<input type="checkbox" className="sr-only" checked={checked} onChange={onChange} />
<div className={`block w-14 h-8 rounded-full ${checked ? 'bg-blue-600' : 'bg-gray-600'} transition-colors duration-300`}></div>
<div className={`dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition-transform duration-300 ${checked ? 'transform translate-x-6' : ''}`}></div>
<input
type="checkbox"
className="sr-only"
checked={checked}
onChange={onChange}
/>
<div
className={`block w-14 h-8 rounded-full ${
checked ? "bg-blue-600" : "bg-gray-600"
} transition-colors duration-300`}
></div>
<div
className={`dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition-transform duration-300 ${
checked ? "transform translate-x-6" : ""
}`}
></div>
</div>
<div className="ml-3 text-gray-300 font-medium">
{checked ? 'Dark' : 'Light'}
{checked ? "Dark" : "Light"}
</div>
</label>
);
@@ -21,10 +35,20 @@ ToggleSwitch.propTypes = {
onChange: PropTypes.func.isRequired,
};
function Navbar({ activeTab, setActiveTab, darkMode, setDarkMode }) {
function Navbar({ darkMode, setDarkMode }) {
const [tabOffset, setTabOffset] = useState(0);
const [tabWidth, setTabWidth] = useState(0);
const tabsRef = useRef([]);
const tabsRef = useRef({});
const location = useLocation();
const getActiveTab = (pathname) => {
if (pathname.startsWith("/regex")) return "regex";
if (pathname.startsWith("/format")) return "format";
if (pathname.startsWith("/settings")) return "settings";
return "settings"; // default to settings if no match
};
const activeTab = getActiveTab(location.pathname);
useEffect(() => {
if (tabsRef.current[activeTab]) {
@@ -39,44 +63,51 @@ function Navbar({ activeTab, setActiveTab, darkMode, setDarkMode }) {
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative">
<div className="flex items-center justify-between h-16">
<div className="flex items-center space-x-8">
<h1 className="text-2xl font-bold text-white">
Profilarr
</h1>
<h1 className="text-2xl font-bold text-white">Profilarr</h1>
<div className="relative flex space-x-2">
<div
className="absolute top-0 bottom-0 bg-gray-900 rounded-md transition-all duration-300"
style={{ left: tabOffset, width: tabWidth }}
></div>
<button
ref={(el) => (tabsRef.current['regex'] = el)}
<Link
to="/regex"
ref={(el) => (tabsRef.current["regex"] = el)}
className={`px-3 py-2 rounded-md text-sm font-medium relative z-10 ${
activeTab === 'regex' ? 'text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'
activeTab === "regex"
? "text-white"
: "text-gray-300 hover:bg-gray-700 hover:text-white"
}`}
onClick={() => setActiveTab('regex')}
>
Regex
</button>
<button
ref={(el) => (tabsRef.current['format'] = el)}
</Link>
<Link
to="/format"
ref={(el) => (tabsRef.current["format"] = el)}
className={`px-3 py-2 rounded-md text-sm font-medium relative z-10 ${
activeTab === 'format' ? 'text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'
activeTab === "format"
? "text-white"
: "text-gray-300 hover:bg-gray-700 hover:text-white"
}`}
onClick={() => setActiveTab('format')}
>
Custom Format
</button>
<button
ref={(el) => (tabsRef.current['settings'] = el)}
</Link>
<Link
to="/settings"
ref={(el) => (tabsRef.current["settings"] = el)}
className={`px-3 py-2 rounded-md text-sm font-medium relative z-10 ${
activeTab === 'settings' ? 'text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'
activeTab === "settings"
? "text-white"
: "text-gray-300 hover:bg-gray-700 hover:text-white"
}`}
onClick={() => setActiveTab('settings')}
>
Settings
</button>
</Link>
</div>
</div>
<ToggleSwitch checked={darkMode} onChange={() => setDarkMode(!darkMode)} />
<ToggleSwitch
checked={darkMode}
onChange={() => setDarkMode(!darkMode)}
/>
</div>
</div>
</nav>
@@ -84,8 +115,6 @@ function Navbar({ activeTab, setActiveTab, darkMode, setDarkMode }) {
}
Navbar.propTypes = {
activeTab: PropTypes.string.isRequired,
setActiveTab: PropTypes.func.isRequired,
darkMode: PropTypes.bool.isRequired,
setDarkMode: PropTypes.func.isRequired,
};