Skip to content

Commit

Permalink
Refactor CSS files and fix style bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
WCY-dt committed May 2, 2024
1 parent 6efbe51 commit d7f2d18
Show file tree
Hide file tree
Showing 17 changed files with 284 additions and 192 deletions.
3 changes: 2 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
root = true

[*]
indent_style = tab
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
Expand Down
38 changes: 18 additions & 20 deletions src/components/clusters.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useContext } from 'react';

import { AppContext } from '../contexts/context';
import LinkCard from '../components/linkCard';
import ClearFilter from '../utils/clearFilter';
import { fetchAndFilterData } from '../services/dataFetcher';

import '../styles/components/clusters.css';
import '../styles/popups/loading.css';

interface ClustersProps {
dataKey: string;
searchTerm: string;
setSearchTerm: (value: string) => void;
isLogedIn: boolean;
token: string;
message: string | null;
setMessage: (value: string | null) => void;
}

function Clusters({ dataKey, searchTerm, setSearchTerm, isLogedIn, token, message, setMessage }: ClustersProps) {
function Clusters({ dataKey }: ClustersProps) {
const {
needReload, setNeedReload,
selectedCategory,
searchTerm
} = useContext(AppContext);

const [clusters, setClusters] = useState<ClusterProps[]>([]);
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);

useEffect(() => {
setIsLoading(true);
fetchAndFilterData(dataKey, true, selectedCategory, searchTerm, setClusters)
.finally(() => setIsLoading(false));
}, [dataKey, selectedCategory, searchTerm]);
fetchAndFilterData(dataKey, false, selectedCategory, searchTerm, setClusters)
.finally(() => {
setIsLoading(false);
if (needReload) {
setNeedReload(false);
}
});
}, [dataKey, selectedCategory, searchTerm, needReload]);

if (isLoading) {
return (
Expand All @@ -37,18 +41,12 @@ function Clusters({ dataKey, searchTerm, setSearchTerm, isLogedIn, token, messag
return (
<>
<h1 className="Clusters-title">{dataKey}</h1>
<ClearFilter {...{ selectedCategory, setSelectedCategory, searchTerm, setSearchTerm }} />
<div className="Clusters-list">
{clusters.length > 0 ? (
clusters.map((cluster: ClusterProps) => (
<LinkCard
key={cluster.Title}
key={cluster.Id}
item={cluster}
setSelectedCategory={setSelectedCategory}
isLogedIn={isLogedIn}
token={token}
message={message}
setMessage={setMessage}
/>
))
) : (
Expand Down
23 changes: 8 additions & 15 deletions src/components/content.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,25 @@
import React from 'react';
import React, { useContext } from 'react';
import { Route, Routes } from 'react-router-dom';

import { AppContext } from '../contexts/context';
import Cluster from '../components/clusters';

import '../styles/components/content.css';

interface ContentProps {
routes: { [key: string]: string };
searchTerm: string;
setSearchTerm: (value: string) => void;
isLogedIn: boolean;
token: string;
setToken: (value: string) => void;
message: string | null;
setMessage: (value: string | null) => void;
setShowOverlay: (value: boolean) => void;
}
function Content() {
const {
routes
} = useContext(AppContext);

function Content({ routes, searchTerm, setSearchTerm, isLogedIn, token, setToken, message, setMessage, setShowOverlay }: ContentProps) {
return (
<div className="App-content">
<Routes>
<Route path="/"
element={<Cluster dataKey={routes[Object.keys(routes)[0]]} searchTerm={searchTerm} setSearchTerm={setSearchTerm} isLogedIn={isLogedIn} token={token} message={message} setMessage={setMessage} />}
element={<Cluster dataKey={routes[Object.keys(routes)[0] as keyof typeof routes] as string} />}
/>
{Object.entries(routes).map(([path, element]) => (
<Route path={path}
element={<Cluster dataKey={element} searchTerm={searchTerm} setSearchTerm={setSearchTerm} isLogedIn={isLogedIn} token={token} message={message} setMessage={setMessage} />}
element={<Cluster dataKey={element as string} />}
/>
))}
</Routes>
Expand Down
47 changes: 22 additions & 25 deletions src/components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect, useRef, useContext } from 'react';
import { Icon } from '@iconify/react';
import { Link } from 'react-router-dom';

import { AppContext } from '../contexts/context';
import Login from '../popups/login';

import '../styles/components/header.css';

interface HeaderProps {
routes: { [key: string]: string };
searchTerm: string;
setSearchTerm: (value: string) => void;
isLogedIn: boolean;
setIsLogedIn: (value: boolean) => void;
token: string;
setToken: (value: string) => void;
message: string | null;
setMessage: (value: string | null) => void;
setShowOverlay: (value: boolean) => void;
}
function Header() {
const {
isLogedIn, setIsLogedIn,
routes,
setToken,
setMessage,
searchTerm, setSearchTerm,
setShowOverlay,
setOverlayAction
} = useContext(AppContext);

function Header({ routes, searchTerm, setSearchTerm, isLogedIn, setIsLogedIn, token, setToken, message, setMessage, setShowOverlay }: HeaderProps) {
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
localStorage.removeItem('colorMap');
if (inputRef.current) {
inputRef.current.focus();
}
Expand All @@ -36,9 +33,6 @@ function Header({ routes, searchTerm, setSearchTerm, isLogedIn, setIsLogedIn, to
const toggleMenu = () => setIsOpen(!isOpen);

const [showLogin, setShowLogin] = useState(false);
const toggleLogin = () => {
setShowLogin(!showLogin);
};
const toggleLogout = () => {
setIsLogedIn(false);
setToken('');
Expand All @@ -57,7 +51,7 @@ function Header({ routes, searchTerm, setSearchTerm, isLogedIn, setIsLogedIn, to
</div>
<ul className="App-nav-list">
{Object.entries(routes).map(([path, element]) => (
<li className="App-nav-item"><Link to={path}>{element}</Link></li>
<li className="App-nav-item"><Link to={path}>{element as React.ReactNode}</Link></li>
))}
</ul>
<div className="App-nav-right">
Expand All @@ -72,22 +66,25 @@ function Header({ routes, searchTerm, setSearchTerm, isLogedIn, setIsLogedIn, to
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
<button className={`App-nav-login`} onClick={isLogedIn ? toggleLogout : toggleLogin} title="Login">{isLogedIn ? <Icon icon="ci:log-out" /> : <Icon icon="ci:user-01" />}</button>
<button className={`App-nav-login`} onClick={isLogedIn ? toggleLogout : () => {
setShowLogin(true);
setShowOverlay(true);
setOverlayAction(() => () => setShowLogin(false));
}} title="Login">{isLogedIn ? <Icon icon="ci:log-out" /> : <Icon icon="ci:user-01" />}</button>
</div>
<button className="App-nav-button" onClick={toggleMenu}>{isOpen ? <Icon icon="ci:window-close" /> : <Icon icon="ci:window-sidebar" />}</button>
<button className="App-nav-button" onClick={toggleMenu} title="Open/Close navigator">{isOpen ? <Icon icon="ci:window-close" /> : <Icon icon="ci:window-sidebar" />}</button>
{isOpen && (
<ul className="App-nav-menu">
{Object.entries(routes).map(([path, element]) => (
<li className="App-nav-item"><Link to={path}>{element}</Link></li>
<li className="App-nav-item"><Link to={path}>{element as React.ReactNode}</Link></li>
))}
</ul>
)}
</nav>
<div className={`overlay ${(isOpen || showLogin) ? 'open' : ''}`} onClick={() => {
<div className={`overlay ${isOpen ? 'open' : ''}`} onClick={() => {
if (isOpen) toggleMenu();
if (showLogin) toggleLogin();
}}></div>
{showLogin && <Login setShowLogin={setShowLogin} setIsLogedIn={setIsLogedIn} token={token} setToken={setToken} message={message} setMessage={setMessage} /> }
{showLogin && <Login setShowLogin={setShowLogin} /> }
</header>
)
}
Expand Down
41 changes: 26 additions & 15 deletions src/components/linkCard.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
import React, { useState } from 'react';
import React, { useContext } from 'react';
import { Icon } from '@iconify/react';
import { v4 as uuidv4 } from 'uuid';

import { AppContext } from '../contexts/context';
import { getRandomColor, getContrastColor } from '../utils/randomColor';
import Confirm from '../popups/confirm';
import deleteCardHandler from '../services/deleteCardHandler';

import '../styles/components/linkCard.css';

interface LinkCardProps {
item: ClusterProps;
setSelectedCategory: (value: string) => void;
isLogedIn: boolean;
token: string;
message: string | null;
setMessage: (value: string | null) => void;
}

function LinkCard({ item, setSelectedCategory, isLogedIn, token, message, setMessage }: LinkCardProps) {
function LinkCard({ item }: LinkCardProps) {
const {
isLogedIn,
token,
setMessage,
setShowConfirm,
setConfirmMessage,
setConfirmAction,
setSelectedCategory,
setShowOverlay,
setOverlayAction
} = useContext(AppContext);

const id = item.Id || 0;

const backgroundColor = getRandomColor(item.Category);
const textColor = getContrastColor(backgroundColor);

Expand All @@ -26,11 +35,7 @@ function LinkCard({ item, setSelectedCategory, isLogedIn, token, message, setMes
setSelectedCategory(item.Category);
};

const [showConfirm, setShowConfirm] = useState<boolean>(false);
const confirmMessage = "Are you confirmed to delete this card?";

const tryDeleteCard = async () => {
const id = item.Id || 0;
const tryDeleteCard = async (id: number) => {
const deleteCardResult = await deleteCardHandler({ id, token });

if (deleteCardResult === true) {
Expand All @@ -43,6 +48,7 @@ function LinkCard({ item, setSelectedCategory, isLogedIn, token, message, setMes
return (
<>
<div className="link-card">
<div id="link-card-id" hidden>{item.Id || 0}</div>
<div className="link-card-left">
<div className="link-card-info">
<div className="link-card-category" style={{ backgroundColor, color: textColor }} onClick={handleCategoryClick}>
Expand All @@ -59,7 +65,13 @@ function LinkCard({ item, setSelectedCategory, isLogedIn, token, message, setMes
{isLogedIn ? (
<div className="link-card-edit">
<Icon icon="ci:edit-pencil-line-01" className="link-card-edit-edit"></Icon>
<Icon icon="ci:trash-full" className="link-card-edit-delete" onClick={() => setShowConfirm(true)}></Icon>
<Icon icon="ci:trash-full" className="link-card-edit-delete" onClick={() => {
setConfirmMessage('Are you sure to delete this card?');
setConfirmAction(() => () => tryDeleteCard(id));
setShowConfirm(true);
setShowOverlay(true);
setOverlayAction(() => () => setShowConfirm(false));
}}></Icon>
</div>
) : null
}
Expand Down Expand Up @@ -100,7 +112,6 @@ function LinkCard({ item, setSelectedCategory, isLogedIn, token, message, setMes
) : null}
</a>
</div>
{showConfirm ? (<Confirm message={confirmMessage} setShowConfirm={setShowConfirm} actionHandler={tryDeleteCard}/>) : null}
</>
);
}
Expand Down
84 changes: 84 additions & 0 deletions src/contexts/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React, { createContext, useState, useEffect } from 'react';
import { fetchCollection } from '../services/collectionFetcher';

export const AppContext = createContext({
isLoading: false,
setIsLoading: (_: boolean) => {},
isLogedIn: false,
setIsLogedIn: (_: boolean) => {},
needReload: false,
setNeedReload: (_: boolean) => {},
routes: {},
setRoutes: (_: {[_: string]: React.ReactNode}) => {},
token: '',
setToken: (_: string) => {},
message: null as string | null,
setMessage: (_: string | null) => {},
showConfirm: false,
setShowConfirm: (_: boolean) => {},
confirmMessage: '',
setConfirmMessage: (_: string) => {},
confirmAction: () => {},
setConfirmAction: (_: () => void) => {},
showOverlay: false,
setShowOverlay: (_: boolean) => {},
overlayAction: () => {},
setOverlayAction: (_: () => void) => {},
selectedCategory: null as string | null,
setSelectedCategory: (_: string | null) => {},
searchTerm: '',
setSearchTerm: (_: string) => {},
});

export const AppProvider = ({ children }: { children: React.ReactNode }) => {
const [isLoading, setIsLoading] = useState<boolean>(true);
const [isLogedIn, setIsLogedIn] = useState<boolean>(false);
const [needReload, setNeedReload] = useState<boolean>(false);
const [routes, setRoutes] = useState({});
const [token, setToken] = useState<string>('');
const [message, setMessage] = useState<string | null>(null);
const [showConfirm, setShowConfirm] = useState<boolean>(false);
const [confirmMessage, setConfirmMessage] = useState<string>('');
const [confirmAction, setConfirmAction] = useState<() => void>(() => () => {});
const [showOverlay, setShowOverlay] = useState<boolean>(false);
const [overlayAction, setOverlayAction] = useState<() => void>(() => () => {});
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const [searchTerm, setSearchTerm] = useState('');

useEffect(() => {
setIsLoading(true);
fetchCollection(setRoutes)
.finally(() => setIsLoading(false));
}, []);

useEffect(() => {
if (localStorage.getItem('token')) {
setIsLogedIn(true);
setToken(localStorage.getItem('token') as string);
}
}, []);

useEffect(() => {
localStorage.removeItem('colorMap');
}, []);

return (
<AppContext.Provider value={{
isLoading, setIsLoading,
isLogedIn, setIsLogedIn,
needReload, setNeedReload,
routes, setRoutes,
token, setToken,
message, setMessage,
showConfirm, setShowConfirm,
confirmMessage, setConfirmMessage,
confirmAction, setConfirmAction,
showOverlay, setShowOverlay,
overlayAction, setOverlayAction,
selectedCategory, setSelectedCategory,
searchTerm, setSearchTerm
}}>
{children}
</AppContext.Provider>
);
};
Loading

0 comments on commit d7f2d18

Please sign in to comment.