diff --git a/package.json b/package.json index 259a35e..2752489 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "@iconify/react": "^5.2.0", "@mantine/core": "^7.17.2", "@mantine/hooks": "^7.17.2", - "@mantine/modals": "^7.17.2", "@tabler/icons-react": "^3.31.0", "@tanstack/react-query": "^5.69.0", "@tanstack/react-query-devtools": "^5.69.0", diff --git a/src/App.tsx b/src/App.tsx index 331fef8..fc30f35 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,7 +4,6 @@ import { createTheme, mergeMantineTheme, } from '@mantine/core'; -import { ModalsProvider } from '@mantine/modals'; import { useCommonHooks, useQueryAPI } from 'hooks'; import { useEffect } from 'react'; import { @@ -20,6 +19,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import './index.css'; import { Homepage, Settings } from 'pages'; import { ToastContainer } from 'react-toastify'; +import type { Theme, ThemePlaylist } from 'types'; function App() { const { data: allThemes, isFetched: isAllThemesFetched } = useQueryAPI({ @@ -62,25 +62,28 @@ function App() { if (allThemes && themeName) { if (currentThemePlaylist === 'All') { if (themeName !== 'random') { - const temp = allThemes.find((t: any) => t.name === themeName); + const temp = allThemes.find((t: Theme) => t.name === themeName); setTheme(temp); } else { handleThemeChange(allThemes, false); } } else if (currentThemePlaylist === 'Time of Day') { const themeList = JSON.parse( - themePlaylists.find((t: any) => t.name === currentThemePlaylist).themeList, + themePlaylists.find((t: ThemePlaylist) => t.name === currentThemePlaylist) + .themeList, ); setTheme( allThemes.find( - (t: any) => t.id === Number(themeList[Math.floor(new Date().getHours() / 6)]), + (t: Theme) => + t.id === Number(themeList[Math.floor(new Date().getHours() / 6)]), ), ); } else { const themeList = JSON.parse( - themePlaylists.find((t: any) => t.name === currentThemePlaylist).themeList, + themePlaylists.find((t: ThemePlaylist) => t.name === currentThemePlaylist) + .themeList, ); - const filteredThemes = allThemes.filter((t: any) => themeList.includes(t.id)); + const filteredThemes = allThemes.filter((t: Theme) => themeList.includes(t.id)); setTheme('random'); handleThemeChange(filteredThemes, false); } @@ -93,10 +96,8 @@ function App() { - - - - + + )} diff --git a/src/components/HelpModal/HelpModal.tsx b/src/components/HelpModal/HelpModal.tsx index 05cee5f..34d92d8 100644 --- a/src/components/HelpModal/HelpModal.tsx +++ b/src/components/HelpModal/HelpModal.tsx @@ -1,6 +1,7 @@ import { Divider, Modal, Stack } from '@mantine/core'; import { useCommonHooks } from 'hooks'; import { modalClasses } from 'styles'; +import type { Provider } from 'types'; import HelpSection from './HelpSection'; export function HelpModal({ @@ -47,7 +48,7 @@ export function HelpModal({ { + items={providerData.map((provider: Provider) => { return { name: provider.name, command: provider.prefix, diff --git a/src/contexts/HomepageFilters.ts b/src/contexts/HomepageFilters.ts deleted file mode 100644 index ac3a585..0000000 --- a/src/contexts/HomepageFilters.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { atom } from 'jotai'; - -export const HomepageFilters = atom([{ value: 'All', label: 'All' }]); diff --git a/src/contexts/index.ts b/src/contexts/index.ts index 2494c5e..09e093b 100644 --- a/src/contexts/index.ts +++ b/src/contexts/index.ts @@ -1,2 +1 @@ -export { HomepageFilters } from './HomepageFilters'; export { appTheme } from './theme'; diff --git a/src/hooks/useCommonHooks.ts b/src/hooks/useCommonHooks.ts index e4f5ee9..9942925 100644 --- a/src/hooks/useCommonHooks.ts +++ b/src/hooks/useCommonHooks.ts @@ -2,8 +2,10 @@ import { useLocalStorage } from '@mantine/hooks'; import { appTheme } from 'contexts'; import { useAtom } from 'jotai'; import { useState } from 'react'; +import { useMutationAPI } from './useAPI'; export function useCommonHooks() { + const { mutateAsync } = useMutationAPI(); const isMobile = window.matchMedia('(max-width: 600px)').matches; const [theme, setTheme] = useAtom(appTheme); const [themeName, setThemeName] = useLocalStorage({ @@ -51,6 +53,25 @@ export function useCommonHooks() { }, }); + const modalStyle = { + '--color-text-pri': theme.primaryColor, + '--color-text-acc': theme.accentColor, + '--color-background': theme.backgroundColor, + '--color-border': theme.borderColor, + '--color-search-background': theme.searchColor, + '--image-background': `url(${theme.backgroundImage})`, + }; + + const urlPattern = new RegExp( + '^(https?:\\/\\/)?' + // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string + '(\\#[-a-z\\d_]*)?$', + 'i', + ); // fragment locator + const handleThemeChange = (themes: any, save: any) => { const enabled = themes .filter((t: any) => t.randomEnabled) @@ -69,11 +90,26 @@ export function useCommonHooks() { } }; + const handleDelete = (item: any, endpoint: any) => { + mutateAsync({ method: 'DELETE', endpoint: endpoint, body: item }); + }; + + function fixDigits(k: any) { + if (k < 10) { + return `0${k}`; + } + return k; + } + return { isMobile, theme, setTheme, + modalStyle, + urlPattern, + fixDigits, handleThemeChange, + handleDelete, themeName, setThemeName, appFilter, diff --git a/src/pages/homepage/Homepage.tsx b/src/pages/homepage/Homepage.tsx index a064f32..ba2b090 100644 --- a/src/pages/homepage/Homepage.tsx +++ b/src/pages/homepage/Homepage.tsx @@ -4,8 +4,13 @@ import CurrentWeather from 'components/WeatherModal/CurrentWeather'; import { useCommonHooks, useOSMAPI, useQueryAPI, useWeatherAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { stackClasses } from 'styles'; -import type { CurrentWeather as CW, OutlookWeather } from 'types'; -import type { ExtendedForecast as EF } from 'types/weather'; +import type { + CurrentWeather as CW, + ExtendedForecast as EF, + Message, + OutlookWeather, + PersonalData, +} from 'types'; import Applications from './components/Applications/Applications'; import Bookmarks from './components/Bookmarks/Bookmarks'; import Header from './components/Header/Header'; @@ -24,11 +29,6 @@ export function Homepage() { } = useQueryAPI({ endpoint: 'api/messages', }); - const [personalData, setPersonalData] = useState(null); - const [messages, setMessages] = useState(null); - const [displayedGreeting, setDisplayedGreeting] = useState(''); - const [weatherModalOpened, { open: openWeatherModal, close: closeWeatherModal }] = - useDisclosure(false); const { appFilter, bookmarkFilter, @@ -37,6 +37,11 @@ export function Homepage() { currentLocation, setCurrentLocation, } = useCommonHooks(); + const [personalData, setPersonalData] = useState(); + const [messages, setMessages] = useState([]); + const [displayedGreeting, setDisplayedGreeting] = useState(''); + const [weatherModalOpened, { open: openWeatherModal, close: closeWeatherModal }] = + useDisclosure(false); const dateOptions: Intl.DateTimeFormatOptions = !isMobile ? { weekday: 'long', @@ -54,23 +59,22 @@ export function Homepage() { useEffect(() => { if (personal && personalIsFetched) { setCurrentUser(personal[0]); - setPersonalData(personal); + setPersonalData(personal[0]); } }, [personal, personalIsFetched]); - useEffect(() => { if (messages && personalData) { setDisplayedGreeting(() => { if (Math.floor(Math.random() * 100) > 10 || messages.length === 0) { switch (Math.floor(new Date().getHours() / 6)) { case 0: - return `Good night, ${personalData?.[0]?.firstName}!`; + return `Good night, ${personalData?.firstName}!`; case 1: - return `Good morning, ${personalData?.[0]?.firstName}!`; + return `Good morning, ${personalData?.firstName}!`; case 2: - return `Good afternoon, ${personalData?.[0]?.firstName}!`; + return `Good afternoon, ${personalData?.firstName}!`; case 3: - return `Good evening, ${personalData?.[0]?.firstName}!`; + return `Good evening, ${personalData?.firstName}!`; } } return messages[Math.floor(Math.random() * messages.length)].message; diff --git a/src/pages/homepage/components/Applications/AppItem.tsx b/src/pages/homepage/components/Applications/AppItem.tsx index 8c62c1e..0c8c476 100644 --- a/src/pages/homepage/components/Applications/AppItem.tsx +++ b/src/pages/homepage/components/Applications/AppItem.tsx @@ -5,9 +5,9 @@ import { useState } from 'react'; import { stackClasses, textClasses } from 'styles'; function AppItem({ url, icon, name }: any) { + const { isMobile } = useCommonHooks(); const [textDecoration, setTextDecoration] = useState('none'); const [hover, setHover] = useState(false); - const { isMobile } = useCommonHooks(); const validUrl = url.startsWith('http://') || url.startsWith('https://') ? url : `http://${url}`; return ( diff --git a/src/pages/homepage/components/Applications/Applications.tsx b/src/pages/homepage/components/Applications/Applications.tsx index e3e1282..892db1a 100644 --- a/src/pages/homepage/components/Applications/Applications.tsx +++ b/src/pages/homepage/components/Applications/Applications.tsx @@ -2,14 +2,15 @@ import { Stack, Text } from '@mantine/core'; import { useCommonHooks, useQueryAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { textClasses } from 'styles'; +import type { Application } from 'types'; import AppItem from './AppItem'; function Applications({ contentType }: any) { const { data: apps, isFetching: isAppsFetching } = useQueryAPI({ endpoint: 'api/apps', }); - const [applicationData, setApplicationData] = useState([]); const { isMobile } = useCommonHooks(); + const [applicationData, setApplicationData] = useState([]); useEffect(() => { if (apps && !isAppsFetching) { diff --git a/src/pages/homepage/components/Bookmarks/Bookmarks.tsx b/src/pages/homepage/components/Bookmarks/Bookmarks.tsx index f1a77cc..0c62f09 100644 --- a/src/pages/homepage/components/Bookmarks/Bookmarks.tsx +++ b/src/pages/homepage/components/Bookmarks/Bookmarks.tsx @@ -2,6 +2,7 @@ import { Stack, Text } from '@mantine/core'; import { useCommonHooks, useQueryAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { textClasses } from 'styles'; +import type { Bookmark, BookmarkGroup } from 'types'; import LinkGroups from './LinkGroups'; function Links({ contentType }: any) { @@ -11,9 +12,9 @@ function Links({ contentType }: any) { const { data: groupData, isFetched: groupsIsFetched } = useQueryAPI({ endpoint: 'api/categories', }); - const [bookmarkData, setBookmarkData] = useState([]); - const [groups, setGroups] = useState([]); const { isMobile } = useCommonHooks(); + const [bookmarkData, setBookmarkData] = useState([]); + const [groups, setGroups] = useState([]); useEffect(() => { if (linkData && linksIsFetched) { @@ -23,10 +24,14 @@ function Links({ contentType }: any) { useEffect(() => { if (groupData && groupsIsFetched) { - const groupList = groupData?.map((category: any) => { + const groupList = groupData?.map((category: BookmarkGroup) => { return category; }); - setGroups(groupList); + setGroups( + groupList.sort((a: BookmarkGroup, b: BookmarkGroup) => + a.categoryIndex > b.categoryIndex ? 1 : -1, + ), + ); } }, [groupData, groupsIsFetched]); @@ -50,24 +55,23 @@ function Links({ contentType }: any) { gridTemplateRows: 'auto', }} > - {groups - .sort((a: any, b: any) => (a.categoryIndex > b.categoryIndex ? 1 : -1)) - .map((category: any) => { - if ( - contentType.includes(category.filterName) || - contentType.includes('All') - ) { - return ( - bookmark.category === category.categoryName, - )} - /> - ); - } - })} + {groups.map((category: BookmarkGroup) => { + if ( + contentType.includes(category.filterName) || + contentType.includes('All') + ) { + return ( + + bookmark.category === category.categoryName, + )} + /> + ); + } + })} )} diff --git a/src/pages/homepage/components/Bookmarks/LinkItem.tsx b/src/pages/homepage/components/Bookmarks/LinkItem.tsx index bec9160..72938a6 100644 --- a/src/pages/homepage/components/Bookmarks/LinkItem.tsx +++ b/src/pages/homepage/components/Bookmarks/LinkItem.tsx @@ -8,8 +8,6 @@ function LinkItem({ link }: any) { classNames={textClasses} component='a' href={link.url} - style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} - w={'min-content'} > {link.name} diff --git a/src/pages/homepage/components/Header/Header.tsx b/src/pages/homepage/components/Header/Header.tsx index daa81c4..97aad7b 100644 --- a/src/pages/homepage/components/Header/Header.tsx +++ b/src/pages/homepage/components/Header/Header.tsx @@ -18,14 +18,7 @@ function Header({ openWeatherModal, }: any) { const [time, setTime] = useState(new Date()); - const { isMobile, currentUser } = useCommonHooks(); - - function fixDigits(k: any) { - if (k < 10) { - return `0${k}`; - } - return k; - } + const { isMobile, currentUser, fixDigits } = useCommonHooks(); useEffect(() => { setInterval(() => { diff --git a/src/pages/homepage/components/Header/LargeHeader.tsx b/src/pages/homepage/components/Header/LargeHeader.tsx index adc9614..b014df7 100644 --- a/src/pages/homepage/components/Header/LargeHeader.tsx +++ b/src/pages/homepage/components/Header/LargeHeader.tsx @@ -5,14 +5,7 @@ import { textClasses } from 'styles'; function LargeHeader({ greet, date, setCurrent, weather, basicWeather }: any) { const [time, setTime] = useState(new Date()); - const { isMobile, currentUser } = useCommonHooks(); - - function fixDigits(k: any) { - if (k < 10) { - return `0${k}`; - } - return k; - } + const { isMobile, currentUser, fixDigits } = useCommonHooks(); useEffect(() => { setInterval(() => { diff --git a/src/pages/homepage/components/Search/Search.tsx b/src/pages/homepage/components/Search/Search.tsx index cb3beaa..230d002 100644 --- a/src/pages/homepage/components/Search/Search.tsx +++ b/src/pages/homepage/components/Search/Search.tsx @@ -12,6 +12,7 @@ import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { FiEdit, FiTrash } from 'react-icons/fi'; import { actionIconClasses, selectClasses } from 'styles'; +import type { Application, Provider } from 'types'; export default function Search({ current, @@ -24,7 +25,7 @@ export default function Search({ const { data: providers, isFetched: providersIsFetched } = useQueryAPI({ endpoint: 'api/providers', }); - const [providerData, setProviderData] = useState([]); + const [providerData, setProviderData] = useState([]); const { data: apps, isFetching: isAppsFetching } = useQueryAPI({ endpoint: 'api/apps', }); @@ -42,6 +43,7 @@ export default function Search({ const [listIndex, setListIndex] = useState(0); const { theme, + urlPattern, providerLabel, setProviderLabel, providerURL, @@ -53,15 +55,6 @@ export default function Search({ } = useCommonHooks(); const [placeholderValue, setPlaceholderValue] = useState(''); const [value, setValue] = useState(0); - const urlPattern = new RegExp( - '^(https?:\\/\\/)?' + // protocol - '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name - '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address - '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path - '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string - '(\\#[-a-z\\d_]*)?$', - 'i', - ); // fragment locator const handleSearchHistoryItem = (item: any) => { const url = @@ -104,7 +97,7 @@ export default function Search({ openWeatherModal(); } else if (providerLabel.startsWith('Launch')) { open( - `https://${applicationData?.find((app: any) => app.baseUrl.substr(1).toLowerCase() === item.target.value.substr(1)).url}`, + `https://${applicationData ?? applicationData.find((app: Application) => app.baseUrl.substring(1).toLowerCase() === item.target.value.substr(1)).url}`, '_self', ); } else if (urlPattern.test(item.target.value)) { @@ -213,11 +206,11 @@ export default function Search({ setProviderPrefix('/g'); } else if (item.target.value.startsWith('/')) { const provider = providerData?.find( - (p: any) => p.prefix === item.target.value.split(' ')[0], + (p: Provider) => p.prefix === item.target.value.split(' ')[0], ); - setProviderLabel(provider?.name || 'Invalid Search'); - setProviderURL(provider?.url); - setProviderPrefix(provider?.prefix); + setProviderLabel(provider?.name ?? 'Invalid Search'); + setProviderURL(provider?.url ?? ''); + setProviderPrefix(provider?.prefix ?? ''); } else if (item.target.value.startsWith('!')) { if (item.target.value === '!w' || item.target.value === '!weather') { setProviderLabel('Show weather'); @@ -255,9 +248,12 @@ export default function Search({ } return options .filter((option: any) => { - const words = option.value.toLowerCase().trim().split(' '); return splittedSearch.every((searchWord) => - words.some((word: any) => word.includes(searchWord)), + option.value + .toLowerCase() + .trim() + .split(' ') + .some((word: any) => word.includes(searchWord)), ); }) .slice(0, 10); diff --git a/src/pages/homepage/components/SettingsButton.tsx b/src/pages/homepage/components/SettingsButton.tsx index b1e3592..448e88d 100644 --- a/src/pages/homepage/components/SettingsButton.tsx +++ b/src/pages/homepage/components/SettingsButton.tsx @@ -24,13 +24,14 @@ import { selectClasses, stackClasses, } from 'styles'; +import type { AppCategory, Theme, ThemePlaylist, WolClient } from 'types'; function SettingsButton() { const { data, isFetched } = useQueryAPI({ endpoint: 'api/appCategories' }); const { data: wolClients, isFetched: wolClientsIsFetched } = useQueryAPI({ endpoint: 'api/wolClients', }); - const [wolClientsData, setWolClientsData] = useState([]); + const [wolClientsData, setWolClientsData] = useState([]); const { data: allThemes, isFetched: isAllThemesFetched } = useQueryAPI({ endpoint: 'api/themes', }); @@ -38,9 +39,9 @@ function SettingsButton() { endpoint: 'api/themePlaylists', }); const { mutateAsync: wakeRequest } = useMutationAPI(); - const [allThemeData, setAllThemeData] = useState([]); + const [allThemeData, setAllThemeData] = useState([]); const [categories, setCategories] = useState([{ value: 'All', label: 'All' }]); - const [selectedClient, setSelectedClient] = useState(wolClients?.[0]); + const [selectedClient, setSelectedClient] = useState(wolClients?.[0]); const [overlayOpened, setOverlayOpened] = useState(false); const navigate = useNavigate(); const notify = (notification: any) => toast(notification, { position: 'bottom-right' }); @@ -50,7 +51,6 @@ function SettingsButton() { setThemeName, handleThemeChange, theme, - setTheme, appFilter, setAppFilter, bookmarkFilter, @@ -69,7 +69,7 @@ function SettingsButton() { useEffect(() => { if (data) { - const list: [any] = data.map((category: any) => { + const list: [any] = data.map((category: AppCategory) => { return { value: category.filterName, label: category.filterName }; }); list.unshift({ value: 'All', label: 'All' }); @@ -232,7 +232,7 @@ function SettingsButton() { value={currentThemePlaylist} data={ themePlaylists - ?.map((playlist: any) => { + ?.map((playlist: ThemePlaylist) => { return { value: playlist.name, label: playlist.name, @@ -254,12 +254,13 @@ function SettingsButton() { setThemeName('random'); } else { const themeList = JSON.parse( - themePlaylists.find((t: any) => t.name === 'Time of Day') - .themeList, + themePlaylists.find( + (t: ThemePlaylist) => t.name === 'Time of Day', + ).themeList, ); setThemeName( allThemes.find( - (t: any) => + (t: Theme) => t.id === Number(themeList[Math.floor(new Date().getHours() / 6)]), ).name, diff --git a/src/pages/settings/components/Applications/Applications.tsx b/src/pages/settings/components/Applications/Applications.tsx index ae7b289..fd71143 100644 --- a/src/pages/settings/components/Applications/Applications.tsx +++ b/src/pages/settings/components/Applications/Applications.tsx @@ -24,6 +24,7 @@ import { textClasses, textInputClasses, } from 'styles'; +import type { Application } from 'types'; import AppSettingsItem from './AppSettingsItem'; import DebouncedApplication from './DebouncedApplication'; @@ -32,27 +33,26 @@ const ApplicationSettings = () => { const { data: apps, isFetching: isAppsFetching } = useQueryAPI({ endpoint: endpoint, }); - const [applicationData, setApplicationData] = useState([]); - const { theme, isMobile } = useCommonHooks(); - const [newApplication, setNewApplication] = useState({ + const [applicationData, setApplicationData] = useState([]); + const { theme, isMobile, modalStyle } = useCommonHooks(); + const [newApplication, setNewApplication] = useState({ + id: undefined, name: '', url: '', icon: '', baseUrl: '', filterName: '', + index: 0, }); const { mutateAsync } = useMutationAPI(); const [searchValue, setSearchValue] = useState(''); const [debouncedSearch] = useDebouncedValue(searchValue, 500); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); - const handleDelete = (application: any) => { - mutateAsync({ method: 'DELETE', endpoint: endpoint, body: application }); - }; useEffect(() => { if (apps && !isAppsFetching) { setApplicationData( - apps.filter((a: any) => + apps.filter((a: Application) => a.name.toLowerCase().includes(debouncedSearch.toLowerCase()), ), ); @@ -70,14 +70,7 @@ const ApplicationSettings = () => { onClose={() => { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -269,7 +262,7 @@ const ApplicationSettings = () => { - {applicationData?.map((application: any) => ( + {applicationData?.map((application: Application) => ( @@ -286,10 +279,7 @@ const ApplicationSettings = () => { - + diff --git a/src/pages/settings/components/Applications/DebouncedApplication.tsx b/src/pages/settings/components/Applications/DebouncedApplication.tsx index 5a49eb3..e7baa3b 100644 --- a/src/pages/settings/components/Applications/DebouncedApplication.tsx +++ b/src/pages/settings/components/Applications/DebouncedApplication.tsx @@ -14,14 +14,15 @@ import { IconTrash } from '@tabler/icons-react'; import { useCommonHooks, useMutationAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { cardClasses, modalClasses, textInputClasses } from 'styles'; +import type { Application } from 'types'; -function DebouncedApplication({ application, handleDelete }: any) { - const { theme, isMobile } = useCommonHooks(); +function DebouncedApplication({ application }: { application: Application }) { + const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks(); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const { mutateAsync } = useMutationAPI(); - const [app, setApp] = useState(application); - const [update, setUpdate] = useState({}); + const [app, setApp] = useState(application); + const [update, setUpdate] = useState(); const [debounced] = useDebouncedValue(update, 1000); useEffect(() => { @@ -47,14 +48,7 @@ function DebouncedApplication({ application, handleDelete }: any) { onClose={() => { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -84,7 +78,7 @@ function DebouncedApplication({ application, handleDelete }: any) { color={'red'} styles={{ label: { color: 'black' } }} onClick={() => { - handleDelete(app); + handleDelete(app, 'api/apps'); closeModal(); }} > diff --git a/src/pages/settings/components/Bookmarks/Bookmarks.tsx b/src/pages/settings/components/Bookmarks/Bookmarks.tsx index 250cf22..e7661a1 100644 --- a/src/pages/settings/components/Bookmarks/Bookmarks.tsx +++ b/src/pages/settings/components/Bookmarks/Bookmarks.tsx @@ -25,20 +25,26 @@ import { textClasses, textInputClasses, } from 'styles'; +import type { Bookmark, BookmarkGroup } from 'types'; import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem'; const BookmarkSettings = () => { const { data: linkData, isFetched: linksIsFetched } = useQueryAPI({ endpoint: 'api/links', }); - const [bookmarks, setBookmarks] = useState([]); + const [bookmarks, setBookmarks] = useState([]); const { data: groupData, isFetched: groupsIsFetched } = useQueryAPI({ endpoint: 'api/categories', }); const [dragging, setDragging] = useState(false); - const [groups, setGroups] = useState([]); - const [newGroup, setNewGroup] = useState({}); - const [groupList, setGroupList] = useState([]); - const { theme, isMobile } = useCommonHooks(); + const [groups, setGroups] = useState([]); + const [newGroup, setNewGroup] = useState({ + id: undefined, + categoryName: '', + categoryIndex: 0, + filterName: '', + }); + const [groupList, setGroupList] = useState([]); + const { theme, isMobile, modalStyle } = useCommonHooks(); const { mutateAsync } = useMutationAPI(); const [searchValue, setSearchValue] = useState(''); const [debouncedGroupSearch] = useDebouncedValue(searchValue, 500); @@ -80,9 +86,13 @@ const BookmarkSettings = () => { useEffect(() => { if (groupData && groupsIsFetched) { setGroups( - groupData.filter((a: any) => - a.categoryName.toLowerCase().includes(debouncedGroupSearch.toLowerCase()), - ), + groupData + .filter((a: BookmarkGroup) => + a.categoryName.toLowerCase().includes(debouncedGroupSearch.toLowerCase()), + ) + .sort((a: BookmarkGroup, b: BookmarkGroup) => + a.categoryIndex > b.categoryIndex ? 1 : -1, + ), ); } }, [groupData, groupsIsFetched, debouncedGroupSearch]); @@ -104,14 +114,7 @@ const BookmarkSettings = () => { onClose={() => { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -282,69 +285,65 @@ const BookmarkSettings = () => { ref={provided.innerRef} {...provided.droppableProps} > - {groups - ?.sort((a: any, b: any) => - a.categoryIndex > b.categoryIndex ? 1 : -1, - ) - .map((group: any) => ( - - {(provided) => ( - ( + + {(provided) => ( + + - - - - - Name - - - {group.categoryName} - - - - - Filter Name - - - {group.filterName} - - - - - - )} - - ))} + + + + Name + + + {group.categoryName} + + + + + Filter Name + + + {group.filterName} + + + + + + )} + + ))} {provided.placeholder} )} @@ -354,17 +353,15 @@ const BookmarkSettings = () => { ) : ( - {groups - ?.sort((a: any, b: any) => (a.categoryIndex > b.categoryIndex ? 1 : -1)) - .map((group: any) => ( - a.category === group.categoryName) - .sort((a: any, b: any) => (a.index > b.index ? 1 : -1))} - /> - ))} + {groups?.map((group: BookmarkGroup) => ( + a.category === group.categoryName) + .sort((a: Bookmark, b: Bookmark) => (a.index > b.index ? 1 : -1))} + /> + ))} )} diff --git a/src/pages/settings/components/Bookmarks/DebouncedBookmarkItem.tsx b/src/pages/settings/components/Bookmarks/DebouncedBookmarkItem.tsx index 76ebe3e..fff4fab 100644 --- a/src/pages/settings/components/Bookmarks/DebouncedBookmarkItem.tsx +++ b/src/pages/settings/components/Bookmarks/DebouncedBookmarkItem.tsx @@ -14,14 +14,15 @@ import { IconTrash } from '@tabler/icons-react'; import { useCommonHooks, useMutationAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { cardClasses, modalClasses, textInputClasses } from 'styles'; +import type { Bookmark } from 'types'; -function DebouncedBookmarkItem({ bookmarkItem, handleDelete }: any) { - const { theme, isMobile } = useCommonHooks(); +function DebouncedBookmarkItem({ bookmarkItem }: { bookmarkItem: Bookmark }) { + const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks(); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const { mutateAsync } = useMutationAPI(); - const [bookmark, setBookmark] = useState(bookmarkItem); - const [update, setUpdate] = useState({}); + const [bookmark, setBookmark] = useState(bookmarkItem); + const [update, setUpdate] = useState({}); const [debounced] = useDebouncedValue(update, 1000); useEffect(() => { @@ -47,14 +48,7 @@ function DebouncedBookmarkItem({ bookmarkItem, handleDelete }: any) { onClose={() => { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -84,7 +78,7 @@ function DebouncedBookmarkItem({ bookmarkItem, handleDelete }: any) { color={'red'} styles={{ label: { color: 'black' } }} onClick={() => { - handleDelete(bookmark); + handleDelete(bookmark, 'api/links'); closeModal(); }} > diff --git a/src/pages/settings/components/Bookmarks/DebouncedGroupSettingsItem.tsx b/src/pages/settings/components/Bookmarks/DebouncedGroupSettingsItem.tsx index b567e6d..4d4787a 100644 --- a/src/pages/settings/components/Bookmarks/DebouncedGroupSettingsItem.tsx +++ b/src/pages/settings/components/Bookmarks/DebouncedGroupSettingsItem.tsx @@ -18,25 +18,29 @@ import { useCommonHooks, useMutationAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { FiPlus } from 'react-icons/fi'; import { buttonClasses, cardClasses, modalClasses, textInputClasses } from 'styles'; +import type { Bookmark, BookmarkGroup } from 'types'; import BookmarkSettingsItem from './BookmarkSettingsItem'; import DebouncedBookmarkItem from './DebouncedBookmarkItem'; -function DebouncedGroupSettingsItem({ bookmarkGroup, bookmarks }: any) { - const { theme, isMobile } = useCommonHooks(); +function DebouncedGroupSettingsItem({ + bookmarkGroup, + bookmarks, +}: { bookmarkGroup: BookmarkGroup; bookmarks: Bookmark[] }) { + const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks(); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [popoverOpened, setPopoverOpened] = useState(false); const { mutateAsync } = useMutationAPI(); - const [group, setGroup] = useState(bookmarkGroup); - const [update, setUpdate] = useState({}); + const [group, setGroup] = useState(bookmarkGroup); + const [update, setUpdate] = useState({}); const [debounced] = useDebouncedValue(update, 1000); - const [newBookmark, setNewBookmark] = useState({}); - const [bookmarkList, setBookmarkList] = useState(bookmarks); - const handleDeleteBookmark = (application: any) => { - mutateAsync({ method: 'DELETE', endpoint: 'api/links', body: application }); - }; - const handleDeleteGroup = (application: any) => { - mutateAsync({ method: 'DELETE', endpoint: 'api/categories', body: application }); - }; + const [newBookmark, setNewBookmark] = useState({ + id: undefined, + name: '', + url: '', + category: group.categoryName, + index: 0, + }); + const [bookmarkList, setBookmarkList] = useState(bookmarks); const reorder = (list: any, startIndex: any, endIndex: any) => { const result = Array.from(list); @@ -95,14 +99,7 @@ function DebouncedGroupSettingsItem({ bookmarkGroup, bookmarks }: any) { onClose={() => { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -132,7 +129,7 @@ function DebouncedGroupSettingsItem({ bookmarkGroup, bookmarks }: any) { color={'red'} styles={{ label: { color: 'black' } }} onClick={() => { - handleDeleteGroup(group); + handleDelete(group, 'api/categories'); closeModal(); }} > @@ -234,47 +231,42 @@ function DebouncedGroupSettingsItem({ bookmarkGroup, bookmarks }: any) { {(provided) => ( - {bookmarks - .sort((a: any, b: any) => (a.index > b.index ? 1 : -1)) - .map((bookmark: any) => ( - - {(provided: any) => ( - - - - - - - - - - - - {provided.placeholder} - - )} - - ))} + {bookmarks.map((bookmark: Bookmark) => ( + + {(provided: any) => ( + + + + + + + + + + + + {provided.placeholder} + + )} + + ))} {provided.placeholder} diff --git a/src/pages/settings/components/Messages/DebouncedMessage.tsx b/src/pages/settings/components/Messages/DebouncedMessage.tsx index 77281d9..8f8acb7 100644 --- a/src/pages/settings/components/Messages/DebouncedMessage.tsx +++ b/src/pages/settings/components/Messages/DebouncedMessage.tsx @@ -14,8 +14,8 @@ import { IconTrash } from '@tabler/icons-react'; import { useCommonHooks } from 'hooks'; import { cardClasses, modalClasses, textInputClasses } from 'styles'; -function DebouncedMessage({ label, message, setMessage, handleDelete }: any) { - const { theme, isMobile } = useCommonHooks(); +function DebouncedMessage({ label, message, setMessage }: any) { + const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks(); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); return ( @@ -28,14 +28,7 @@ function DebouncedMessage({ label, message, setMessage, handleDelete }: any) { onClose={() => { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -65,7 +58,7 @@ function DebouncedMessage({ label, message, setMessage, handleDelete }: any) { color={'red'} styles={{ label: { color: 'black' } }} onClick={() => { - handleDelete(message); + handleDelete(message, 'api/messages'); closeModal(); }} > diff --git a/src/pages/settings/components/Messages/Messages.tsx b/src/pages/settings/components/Messages/Messages.tsx index 4ef5144..2d09426 100644 --- a/src/pages/settings/components/Messages/Messages.tsx +++ b/src/pages/settings/components/Messages/Messages.tsx @@ -24,14 +24,15 @@ import { textClasses, textInputClasses, } from 'styles'; +import type { Message } from 'types'; const MessageSettings = () => { const endpoint = 'api/messages'; const { data: messageData, isFetched: isMessagesFetched } = useQueryAPI({ - endpoint: 'api/messages', + endpoint: endpoint, }); - const { theme, isMobile } = useCommonHooks(); + const { theme, isMobile, modalStyle } = useCommonHooks(); const { mutateAsync } = useMutationAPI(); - const [messages, setMessages] = useState([]); + const [messages, setMessages] = useState([]); const [newMessage, setNewMessage] = useState(''); const [newMessageError, setNewMessageError] = useState(''); const [message, setMessage] = useState({}); @@ -40,14 +41,10 @@ const MessageSettings = () => { const [debouncedSearch] = useDebouncedValue(searchValue, 500); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); - const handleDelete = (message: any) => { - mutateAsync({ method: 'DELETE', endpoint: endpoint, body: message }); - }; - useEffect(() => { if (messageData && isMessagesFetched) { setMessages( - messageData.filter((m: any) => + messageData.filter((m: Message) => m.message.toLowerCase().includes(debouncedSearch.toLowerCase()), ), ); @@ -71,14 +68,7 @@ const MessageSettings = () => { onClose={() => { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -203,13 +193,12 @@ const MessageSettings = () => { - {messages?.map((message: any) => ( + {messages?.map((message: Message) => ( ))} diff --git a/src/pages/settings/components/Personalization/Personalization.tsx b/src/pages/settings/components/Personalization/Personalization.tsx index 0b39463..a98c3cb 100644 --- a/src/pages/settings/components/Personalization/Personalization.tsx +++ b/src/pages/settings/components/Personalization/Personalization.tsx @@ -3,6 +3,7 @@ import { useDebouncedValue } from '@mantine/hooks'; import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { cardClasses, textClasses, textInputClasses } from 'styles'; +import type { PersonalData } from 'types'; const PersonalizationSettings = () => { const endpoint = 'api/personalData'; const { @@ -12,8 +13,8 @@ const PersonalizationSettings = () => { } = useQueryAPI({ endpoint: endpoint, }); - const [personal, setPersonal] = useState({}); - const [update, setUpdate] = useState({}); + const [personal, setPersonal] = useState(); + const [update, setUpdate] = useState({}); const [debounced] = useDebouncedValue(update, 1000); const { mutateAsync: editRow } = useMutationAPI(); const { isMobile } = useCommonHooks(); diff --git a/src/pages/settings/components/Search/DebouncedSearchProvider.tsx b/src/pages/settings/components/Search/DebouncedSearchProvider.tsx index b5dc9c9..2b03ec7 100644 --- a/src/pages/settings/components/Search/DebouncedSearchProvider.tsx +++ b/src/pages/settings/components/Search/DebouncedSearchProvider.tsx @@ -14,14 +14,15 @@ import { IconTrash } from '@tabler/icons-react'; import { useCommonHooks, useMutationAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { cardClasses, modalClasses, textInputClasses } from 'styles'; +import type { Provider } from 'types'; -function DebouncedSearchProvider({ searchProvider, handleDelete }: any) { - const { theme, isMobile } = useCommonHooks(); +function DebouncedSearchProvider({ searchProvider }: any) { + const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks(); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const { mutateAsync } = useMutationAPI(); - const [provider, setProvider] = useState(searchProvider); - const [update, setUpdate] = useState({}); + const [provider, setProvider] = useState(searchProvider); + const [update, setUpdate] = useState({}); const [debounced] = useDebouncedValue(update, 1000); useEffect(() => { @@ -47,14 +48,7 @@ function DebouncedSearchProvider({ searchProvider, handleDelete }: any) { onClose={() => { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -84,7 +78,7 @@ function DebouncedSearchProvider({ searchProvider, handleDelete }: any) { color={'red'} styles={{ label: { color: 'black' } }} onClick={() => { - handleDelete(provider); + handleDelete(provider, 'api/providers'); closeModal(); }} > diff --git a/src/pages/settings/components/Search/SearchProviders.tsx b/src/pages/settings/components/Search/SearchProviders.tsx index 76ddbac..7baf004 100644 --- a/src/pages/settings/components/Search/SearchProviders.tsx +++ b/src/pages/settings/components/Search/SearchProviders.tsx @@ -24,6 +24,7 @@ import { textClasses, textInputClasses, } from 'styles'; +import type { Provider } from 'types'; import DebouncedSearchProvider from './DebouncedSearchProvider'; import SearchProviderSettingsItem from './SearchProviderSettingsItem'; @@ -32,20 +33,23 @@ const SearchProviderSettings = () => { const { data: providers, isFetched: providersIsFetched } = useQueryAPI({ endpoint: endpoint, }); - const [providerData, setProviderData] = useState([]); - const { theme, isMobile } = useCommonHooks(); + const [providerData, setProviderData] = useState([]); + const { theme, isMobile, modalStyle } = useCommonHooks(); const { mutateAsync } = useMutationAPI(); - const [newProvider, setNewProvider] = useState({}); + const [newProvider, setNewProvider] = useState({ + id: undefined, + name: '', + url: '', + prefix: '', + }); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [searchValue, setSearchValue] = useState(''); const [debouncedSearch] = useDebouncedValue(searchValue, 500); - const handleDelete = (application: any) => { - mutateAsync({ method: 'DELETE', endpoint: endpoint, body: application }); - }; + useEffect(() => { if (providers && providersIsFetched) { setProviderData( - providers.filter((a: any) => + providers.filter((a: Provider) => a.name.toLowerCase().includes(debouncedSearch.toLowerCase()), ), ); @@ -63,14 +67,7 @@ const SearchProviderSettings = () => { onClose={() => { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -224,7 +221,7 @@ const SearchProviderSettings = () => { - {providerData?.map((provider: any) => ( + {providerData?.map((provider: Provider) => ( @@ -237,10 +234,7 @@ const SearchProviderSettings = () => { - + diff --git a/src/pages/settings/components/Theming/ThemeCard.tsx b/src/pages/settings/components/Theming/ThemeCard.tsx index bfa27a2..bb7d7c0 100644 --- a/src/pages/settings/components/Theming/ThemeCard.tsx +++ b/src/pages/settings/components/Theming/ThemeCard.tsx @@ -13,6 +13,7 @@ import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; import { useState } from 'react'; import { FiEdit, FiShuffle, FiTrash, FiX } from 'react-icons/fi'; import { actionIconClasses, modalClasses } from 'styles'; +import type { ThemePlaylist } from 'types'; function ThemeCard({ cardTheme, handleOpen, allThemes }: any) { const { data: themePlaylists } = useQueryAPI({ @@ -31,10 +32,9 @@ function ThemeCard({ cardTheme, handleOpen, allThemes }: any) { isMobile, currentThemePlaylist, setCurrentThemePlaylist, + modalStyle, + handleDelete, } = useCommonHooks(); - const handleDelete = (application: any) => { - mutateAsync({ method: 'DELETE', endpoint: 'api/themes', body: application }); - }; return ( { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -92,7 +85,7 @@ function ThemeCard({ cardTheme, handleOpen, allThemes }: any) { color={'red'} styles={{ label: { color: 'black' } }} onClick={() => { - handleDelete(cardTheme); + handleDelete(cardTheme, 'api/themes'); closeModal(); }} > @@ -299,8 +292,9 @@ function ThemeCard({ cardTheme, handleOpen, allThemes }: any) { { const themeList = JSON.parse( - themePlaylists.find((t: any) => t.name === currentThemePlaylist) - .themeList, + themePlaylists.find( + (t: ThemePlaylist) => t.name === currentThemePlaylist, + ).themeList, ); const filteredThemes = allThemes.filter((t: any) => themeList.includes(t.id), diff --git a/src/pages/settings/components/Theming/ThemePlaylistCard.tsx b/src/pages/settings/components/Theming/ThemePlaylistCard.tsx index bda76f9..9a1e4bf 100644 --- a/src/pages/settings/components/Theming/ThemePlaylistCard.tsx +++ b/src/pages/settings/components/Theming/ThemePlaylistCard.tsx @@ -17,16 +17,21 @@ import ThemeMiniCard from './ThemeMiniCard'; function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) { const [hover, setHover] = useState(false); - const { setThemeName, setCurrentThemePlaylist, theme, isMobile } = useCommonHooks(); + const { + setThemeName, + setCurrentThemePlaylist, + theme, + isMobile, + modalStyle, + handleDelete, + } = useCommonHooks(); const syncableLists = ['All', 'Backgrounds', 'No Backgrounds']; const { mutateAsync } = useMutationAPI(); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const themeList = JSON.parse( cardPlaylist.themeList.name === 'Time of Day' ? '[]' : cardPlaylist.themeList, ); - const handleDelete = (application: any) => { - mutateAsync({ method: 'DELETE', endpoint: 'api/themePlaylists', body: application }); - }; + return ( { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -83,7 +81,7 @@ function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) { color={'red'} styles={{ label: { color: 'black' } }} onClick={() => { - handleDelete(cardPlaylist); + handleDelete(cardPlaylist, 'api/themePlaylists'); closeModal(); }} > diff --git a/src/pages/settings/components/Theming/ThemePlaylists.tsx b/src/pages/settings/components/Theming/ThemePlaylists.tsx index 1277535..1775d94 100644 --- a/src/pages/settings/components/Theming/ThemePlaylists.tsx +++ b/src/pages/settings/components/Theming/ThemePlaylists.tsx @@ -14,6 +14,7 @@ import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; import { useState } from 'react'; import { FiChevronRight, FiHelpCircle, FiPlus } from 'react-icons/fi'; import { actionIconClasses, buttonClasses, textClasses, textInputClasses } from 'styles'; +import type { ThemePlaylist } from 'types'; import ThemePlaylistCard from './ThemePlaylistCard'; import ThemePlaylistModal from './ThemePlaylistModal'; @@ -140,11 +141,11 @@ function ThemePlaylists() { {themePlaylists - ?.filter((playlist: any) => playlist.default === 1) - ?.filter((a: any) => + ?.filter((playlist: ThemePlaylist) => playlist.default === 1) + ?.filter((a: ThemePlaylist) => a.name.toLowerCase().includes(debouncedSearch.toLowerCase()), ) - .map((cardPlaylist: any) => { + .map((cardPlaylist: ThemePlaylist) => { return ( {cardPlaylist.name === currentThemePlaylist && ( @@ -184,11 +185,11 @@ function ThemePlaylists() { {themePlaylists - ?.filter((playlist: any) => playlist.default === 0) - ?.filter((a: any) => + ?.filter((playlist: ThemePlaylist) => playlist.default === 0) + ?.filter((a: ThemePlaylist) => a.name.toLowerCase().includes(debouncedSearch.toLowerCase()), ) - .map((cardPlaylist: any) => { + .map((cardPlaylist: ThemePlaylist) => { return ( {cardPlaylist.name === currentThemePlaylist && ( diff --git a/src/pages/settings/components/Theming/Themes.tsx b/src/pages/settings/components/Theming/Themes.tsx index 2e75a19..0fcc0ee 100644 --- a/src/pages/settings/components/Theming/Themes.tsx +++ b/src/pages/settings/components/Theming/Themes.tsx @@ -19,6 +19,7 @@ import '@mantine/core/styles/ModalBase.css'; import '@mantine/core/styles/Modal.css'; import { FaDice } from 'react-icons/fa'; import { actionIconClasses, buttonClasses, textClasses, textInputClasses } from 'styles'; +import type { Theme } from 'types'; import ThemeCard from './ThemeCard'; import ThemeModal from './ThemeModal'; function ThemesSettings() { @@ -32,7 +33,7 @@ function ThemesSettings() { const [opened, { open, close }] = useDisclosure(false); const [colorId, setColorId] = useState(''); const [colorValue, setColorValue] = useState('#000000'); - const [backgroundList, setBackgroundList] = useState(['None']); + const [backgroundList, setBackgroundList] = useState(['None']); const [selectedTheme, setSelectedTheme] = useState({}); const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false); const [searchValue, setSearchValue] = useState(''); @@ -40,7 +41,7 @@ function ThemesSettings() { const { currentTheme, setCurrentTheme, theme, isMobile, setCurrentThemePlaylist } = useCommonHooks(); - const handleOpen = (theme: any) => { + const handleOpen = (theme: Theme) => { setSelectedTheme(theme); open(); }; @@ -192,10 +193,10 @@ function ThemesSettings() { pos={'absolute'} /> {allThemes - ?.filter((a: any) => + ?.filter((a: Theme) => a.name.toLowerCase().includes(debouncedSearch.toLowerCase()), ) - .map((cardTheme: any) => ( + .map((cardTheme: Theme) => ( {cardTheme.name === currentTheme && ( { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -84,7 +77,7 @@ function DebouncedWolClient({ wolClient, handleDelete }: any) { color={'red'} styles={{ label: { color: 'black' } }} onClick={() => { - handleDelete(client); + handleDelete(client, 'api/WolClients'); closeModal(); }} > diff --git a/src/pages/settings/components/WoL/WolClients.tsx b/src/pages/settings/components/WoL/WolClients.tsx index 2dc9ae8..8c6decc 100644 --- a/src/pages/settings/components/WoL/WolClients.tsx +++ b/src/pages/settings/components/WoL/WolClients.tsx @@ -24,6 +24,7 @@ import { textClasses, textInputClasses, } from 'styles'; +import type { WolClient } from 'types'; import DebouncedWolClient from './DebouncedWolClient'; import WolClientSettingsItem from './WolClientSettingsItem'; @@ -32,23 +33,22 @@ const WolClientSettings = () => { const { data: wolClientsData, isFetched: wolClientsIsFetched } = useQueryAPI({ endpoint: endpoint, }); - const [wolClients, setWolClients] = useState([]); + const [wolClients, setWolClients] = useState([]); const { mutateAsync } = useMutationAPI(); - const { theme, isMobile } = useCommonHooks(); - const [newWolClient, setNewWolClient] = useState({ + const { theme, isMobile, modalStyle } = useCommonHooks(); + const [newWolClient, setNewWolClient] = useState({ + id: undefined, hostname: '', macAddress: '', }); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [searchValue, setSearchValue] = useState(''); const [debouncedSearch] = useDebouncedValue(searchValue, 500); - const handleDelete = (application: any) => { - mutateAsync({ method: 'DELETE', endpoint: endpoint, body: application }); - }; + useEffect(() => { if (wolClientsData && wolClientsIsFetched) { setWolClients( - wolClientsData.filter((a: any) => + wolClientsData.filter((a: WolClient) => a.hostname.toLowerCase().includes(debouncedSearch.toLowerCase()), ), ); @@ -66,14 +66,7 @@ const WolClientSettings = () => { onClose={() => { closeModal(); }} - style={{ - '--color-text-pri': theme.primaryColor, - '--color-text-acc': theme.accentColor, - '--color-background': theme.backgroundColor, - '--color-border': theme.borderColor, - '--color-search-background': theme.searchColor, - '--image-background': `url(${theme.backgroundImage})`, - }} + style={modalStyle} closeOnEscape closeOnClickOutside > @@ -210,7 +203,7 @@ const WolClientSettings = () => { - {wolClients?.map((client: any) => ( + {wolClients?.map((client: WolClient) => ( @@ -223,7 +216,7 @@ const WolClientSettings = () => { - + diff --git a/src/styles/ActionIcon.module.css b/src/styles/ActionIcon.module.css index 7827876..4809a1a 100644 --- a/src/styles/ActionIcon.module.css +++ b/src/styles/ActionIcon.module.css @@ -19,23 +19,6 @@ } } -.editButton { - &.root { - background-color: var(--color-text-acc) !important; - color: var(--color-text-pri) !important; - .icon { - font-size: 24px; - } - .loader { - display: none; - } - :hover { - background-color: var(--color-text-pri) !important; - color: var(--color-text-acc) !important; - } - } -} - .themeEditButton { &.root { background-color: white !important; diff --git a/src/styles/Button.module.css b/src/styles/Button.module.css index 9b23b2a..6478483 100644 --- a/src/styles/Button.module.css +++ b/src/styles/Button.module.css @@ -19,20 +19,6 @@ } } -.themeButton { - &.root { - font-size: 1em; - font-weight: 500; - margin: 10px; - width: 128px; - line-height: 3rem; - text-align: center; - text-transform: uppercase; - border-radius: 1em; - height: 3.5rem; - } -} - .wakeButton { &.root { font-size: 1em; diff --git a/src/styles/NavLink.module.css b/src/styles/NavLink.module.css deleted file mode 100644 index 7ed0ce4..0000000 --- a/src/styles/NavLink.module.css +++ /dev/null @@ -1,22 +0,0 @@ -.defaultNavLink { - &.root { - display: flex; - align-items: center; - justify-content: space-between; - border-radius: 4px; - color: var(--color-text-pri); - background-color: var(--color-background); - cursor: pointer; - } - - &.root:hover { - border-radius: 4px; - color: var(--color-background); - background-color: var(--color-text-acc); - } - - &.chevron { - width: 10px !important; - height: 10px !important; - } -} diff --git a/src/styles/Stack.module.css b/src/styles/Stack.module.css index 3c219d5..7a04520 100644 --- a/src/styles/Stack.module.css +++ b/src/styles/Stack.module.css @@ -47,46 +47,6 @@ } } -.settingsContainer { - align-items: stretch; - display: grid; - grid-column-gap: 20px; - grid-row-gap: 1vh; - grid-template-columns: 25% 100%; - grid-template-rows: 8vh auto; - justify-items: stretch; - margin-left: auto; - margin-right: auto; - margin-top: 2vh; - margin-bottom: 0px; - width: 75%; - padding-top: .3em; -} - -.settingsNav { - align-items: stretch; - display: grid !important; - grid-column-gap: 20px; - grid-row-gap: 1vh; - grid-template-columns: 1fr; - grid-template-rows: 1fr 14fr 1fr; - justify-items: center; - margin-left: 0em; - margin-right: 0em; - height: 95vh; - background-color: var(--color-search-background); - border-radius: 1em; -} - -.navItem { - gap: 0; - line-height: 1.5rem; - margin: 0; - width: 100%; - text-align: center; - display: flex; -} - .menuStack { width: 40%; height: 150px; diff --git a/src/styles/Text.module.css b/src/styles/Text.module.css index 1a3d0c6..4a65db9 100644 --- a/src/styles/Text.module.css +++ b/src/styles/Text.module.css @@ -87,6 +87,9 @@ font-size: 14px; line-height: 2; color: var(--color-text-pri); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; &:hover { text-decoration: underline; } @@ -110,28 +113,7 @@ } } -.settingsLink { - &.root { - font-size: 1.25em; - display: block; - margin-left: 0; - margin-right: 0; - line-height: 2; - justify-self: center; - color: var(--color-text-pri); - border-radius: 1em; - &:hover { - background-color: var(--color-text-acc); - } - } -} - a { color: var(--color-text-pri); text-decoration: none; } - -a:hover #app-address { - text-decoration: underline; - text-decoration-color: var(--color-border); -} diff --git a/src/styles/index.ts b/src/styles/index.ts index 06bb626..a89c95a 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -5,7 +5,6 @@ import cardClasses from './Card.module.css'; import menuClasses from './Menu.module.css'; import modalClasses from './Modal.module.css'; import multiSelectClasses from './MultiSelect.module.css'; -import navLinkClasses from './NavLink.module.css'; import popoverClasses from './Popover.module.css'; import selectClasses from './Select.module.css'; import stackClasses from './Stack.module.css'; @@ -21,7 +20,6 @@ export { menuClasses, modalClasses, multiSelectClasses, - navLinkClasses, popoverClasses, selectClasses, stackClasses, diff --git a/src/types/application.ts b/src/types/application.ts new file mode 100644 index 0000000..f60176a --- /dev/null +++ b/src/types/application.ts @@ -0,0 +1,13 @@ +export interface Application { + id: number | undefined; + name: string; + url: string; + icon: string; + baseUrl: string; + filterName: string; + index: number; +} + +export interface AppCategory { + filterName: string; +} diff --git a/src/types/bookmark.ts b/src/types/bookmark.ts new file mode 100644 index 0000000..4065047 --- /dev/null +++ b/src/types/bookmark.ts @@ -0,0 +1,7 @@ +export interface Bookmark { + id: number | undefined; + name: string; + url: string; + index: number; + category: string; +} diff --git a/src/types/bookmarkGroup.ts b/src/types/bookmarkGroup.ts new file mode 100644 index 0000000..3640e40 --- /dev/null +++ b/src/types/bookmarkGroup.ts @@ -0,0 +1,6 @@ +export interface BookmarkGroup { + id: number | undefined; + categoryName: string; + categoryIndex: number; + filterName: string; +} diff --git a/src/types/index.ts b/src/types/index.ts index 6f6c067..fd14598 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1 +1,10 @@ -export type { CurrentWeather, OutlookWeather } from './weather'; +export type { CurrentWeather, OutlookWeather, ExtendedForecast } from './weather'; +export type { Application, AppCategory } from './application'; +export type { Bookmark } from './bookmark'; +export type { BookmarkGroup } from './bookmarkGroup'; +export type { PersonalData } from './personalData'; +export type { Message } from './message'; +export type { Provider } from './provider'; +export type { Theme, ThemePlaylist } from './theme'; +export type { WolClient } from './wolClient'; +export type { SearchHistoryItem } from './searchHistory'; diff --git a/src/types/message.ts b/src/types/message.ts new file mode 100644 index 0000000..28dc498 --- /dev/null +++ b/src/types/message.ts @@ -0,0 +1,5 @@ +export interface Message { + id: number; + message: string; + customGreeting: number; +} diff --git a/src/types/personalData.ts b/src/types/personalData.ts new file mode 100644 index 0000000..0897123 --- /dev/null +++ b/src/types/personalData.ts @@ -0,0 +1,6 @@ +export interface PersonalData { + firstName: string; + lastName: string; + email: string; + physicalAddress: string; +} diff --git a/src/types/provider.ts b/src/types/provider.ts new file mode 100644 index 0000000..c1a0d2a --- /dev/null +++ b/src/types/provider.ts @@ -0,0 +1,6 @@ +export interface Provider { + id: number | undefined; + name: string; + url: string; + prefix: string; +} diff --git a/src/types/searchHistory.ts b/src/types/searchHistory.ts new file mode 100644 index 0000000..4095b4e --- /dev/null +++ b/src/types/searchHistory.ts @@ -0,0 +1,7 @@ +export interface SearchHistoryItem { + id: number | undefined; + prefix: string; + provider: string; + searchTerm: string; + dateTimeStamp: string; +} diff --git a/src/types/theme.ts b/src/types/theme.ts new file mode 100644 index 0000000..ea45f2c --- /dev/null +++ b/src/types/theme.ts @@ -0,0 +1,18 @@ +export interface Theme { + id: number | undefined; + name: string; + backgroundImage: string; + backgroundColor: string; + primaryColor: string; + accentColor: string; + borderColor: string; + searchColor: string; + randomEnabled: number; +} + +export interface ThemePlaylist { + id: number | undefined; + name: string; + default: number; + themeList: number[]; +} diff --git a/src/types/wolClient.ts b/src/types/wolClient.ts new file mode 100644 index 0000000..ab5d147 --- /dev/null +++ b/src/types/wolClient.ts @@ -0,0 +1,5 @@ +export interface WolClient { + id: number | undefined; + hostname: string; + macAddress: string; +}