More typing and fixes

This commit is contained in:
Sean Edmunds
2025-04-25 15:02:00 -05:00
parent 74893ac68d
commit b280909ec9
31 changed files with 230 additions and 110 deletions

View File

@@ -7,6 +7,7 @@ import { stackClasses } from 'styles';
import type {
CurrentWeather as CW,
ExtendedForecast as EF,
ExtendedForecast,
Message,
PersonalData,
} from 'types';
@@ -177,7 +178,7 @@ export function Homepage() {
useEffect(() => {
if (forecast) {
setExtendedForecast(
forecast.properties.periods.map((item: any) => ({
forecast.properties.periods.map((item: ExtendedForecast) => ({
detailedForecast: item.detailedForecast,
isDaytime: item.isDaytime,
name: item.name,
@@ -196,6 +197,7 @@ export function Homepage() {
});
}
}, [forecast]);
return (
<Stack
gap={0}

View File

@@ -5,7 +5,7 @@ import { textClasses } from 'styles';
import type { Application } from 'types';
import AppItem from './AppItem';
function Applications({ contentType }: { contentType: [string] }) {
function Applications({ contentType }: { contentType: string[] }) {
const { data: apps, isFetching: isAppsFetching } = useQueryAPI({
endpoint: 'api/apps',
});
@@ -17,16 +17,24 @@ function Applications({ contentType }: { contentType: [string] }) {
setApplicationData(
apps
.filter((a: Application) => a.enabled === 1)
.sort((a: any, b: any) => {
.sort((a: Application, b: Application) => {
switch (appSort) {
case 'A>Z':
return a.name > b.name ? 1 : -1;
case 'Z>A':
return a.name < b.name ? 1 : -1;
case 'Newest':
return a.id < b.id ? 1 : -1;
if (a.id && b.id) {
return a.id < b.id ? 1 : -1;
}
return -1;
case 'Oldest':
return a.id > b.id ? 1 : -1;
if (a.id && b.id) {
return a.id > b.id ? 1 : -1;
}
return -1;
case 'Custom':
return a.index > b.index ? 1 : -1;
}

View File

@@ -5,7 +5,7 @@ import { textClasses } from 'styles';
import type { Bookmark, BookmarkGroup } from 'types';
import LinkGroups from './LinkGroups';
function Links({ contentType }: { contentType: [string] }) {
function Links({ contentType }: { contentType: string[] }) {
const { data: linkData, isFetched: linksIsFetched } = useQueryAPI({
endpoint: 'api/links',
});
@@ -28,18 +28,26 @@ function Links({ contentType }: { contentType: [string] }) {
return category;
});
setGroups(
groupList.sort((a: any, b: any) => {
groupList.sort((a: BookmarkGroup, b: BookmarkGroup) => {
switch (bookmarkSort) {
case 'A>Z':
return a.categoryName > b.categoryName ? 1 : -1;
case 'Z>A':
return a.categoryName < b.categoryName ? 1 : -1;
case 'Newest':
return a.id < b.id ? 1 : -1;
if (a.id && b.id) {
return a.id < b.id ? 1 : -1;
}
return -1;
case 'Oldest':
return a.id > b.id ? 1 : -1;
if (a.id && b.id) {
return a.id > b.id ? 1 : -1;
}
return -1;
case 'Custom':
return a.index > b.index ? 1 : -1;
return a.categoryIndex > b.categoryIndex ? 1 : -1;
}
}),
);

View File

@@ -2,7 +2,7 @@ import { Group, Stack, Text } from '@mantine/core';
import { useCommonHooks } from 'hooks';
import { useEffect, useState } from 'react';
import { textClasses } from 'styles';
import type { CurrentWeather as CW } from 'types';
import type { CurrentWeather } from 'types';
function Header({
greet,
@@ -15,8 +15,8 @@ function Header({
}: {
greet: string;
date: string;
current: CW;
setCurrent: (current: CW) => void;
current: CurrentWeather;
setCurrent: (current: CurrentWeather) => void;
weather: any;
basicWeather: any;
openWeatherModal: () => void;

View File

@@ -67,11 +67,11 @@ export default function Search({
const [placeholderValue, setPlaceholderValue] = useState('');
const [value, setValue] = useState(0);
const handleSearchHistoryItem = (item: any) => {
const handleSearchHistoryItem = ({ option }: { option: SearchHistoryItem }) => {
const url =
providers.find((provider: Provider) => provider.prefix === item.option.prefix)
?.url ?? 'https://www.google.com/search?q=';
open(`${url}${item.option.searchTerm}`, '_self');
providers.find((provider: Provider) => provider.prefix === option.prefix)?.url ??
'https://www.google.com/search?q=';
open(`${url}${option.searchTerm}`, '_self');
};
const handleAppSearchItem = (item: any) => {
@@ -425,7 +425,7 @@ export default function Search({
useEffect(() => {
const splittedSearch = searchValue.toLowerCase().trim().split(' ');
const filtered = searchHistory
.filter((item: any) => {
.filter((item: SearchHistoryItem) => {
const option = `${item.prefix} ${item.searchTerm}`;
const words = option.toLowerCase().trim().split(' ');
return splittedSearch.every((searchWord) =>
@@ -450,7 +450,7 @@ export default function Search({
<Select
classNames={selectClasses}
className={selectClasses.search}
data={searchHistory.map((item: any) => ({
data={searchHistory.map((item: SearchHistoryItem) => ({
label: `${item.provider}`,
value: `${item.prefix} ${item.searchTerm} ${item.dateTimeStamp}`,
...item,

View File

@@ -1,6 +1,7 @@
import {
ActionIcon,
Button,
type ComboboxItem,
Group,
Menu,
MultiSelect,
@@ -169,7 +170,9 @@ function SettingsButton() {
macAddress: wolClient.macAddress,
};
})
.toSorted((a: any, b: any) => a.label.localeCompare(b.label)) || []
.toSorted((a: ComboboxItem, b: ComboboxItem) =>
a.label.localeCompare(b.label),
) ?? []
}
w='92%'
classNames={{
@@ -179,8 +182,6 @@ function SettingsButton() {
option: selectClasses.menuSelectOption,
}}
comboboxProps={{ withinPortal: false }}
onChange={(_value, option: any) => setSelectedClient(option)}
onLoad={(option: any) => setSelectedClient(option)}
/>
</Stack>
<Stack
@@ -252,7 +253,9 @@ function SettingsButton() {
label: playlist.name,
};
})
.toSorted((a: any, b: any) => a.label.localeCompare(b.label)) ?? []
.toSorted((a: ComboboxItem, b: ComboboxItem) =>
a.label.localeCompare(b.label),
) ?? []
}
w='92%'
classNames={{
@@ -262,7 +265,7 @@ function SettingsButton() {
option: selectClasses.menuSelectOption,
}}
comboboxProps={{ withinPortal: false }}
onChange={(_value, option: any) => {
onChange={(_value, option: ComboboxItem) => {
setCurrentThemePlaylist(option.value);
if (option.value !== 'Time of Day') {
setThemeName('random');
@@ -281,7 +284,6 @@ function SettingsButton() {
);
}
}}
onLoad={(option: any) => setCurrentThemePlaylist(option)}
/>
</Stack>
</Stack>
@@ -329,7 +331,7 @@ function SettingsButton() {
<MultiSelect
label='Filter'
data={
categories.toSorted((a: any, b: any) =>
categories.toSorted((a: ComboboxItem, b: ComboboxItem) =>
a.label.localeCompare(b.label),
) ?? []
}
@@ -341,7 +343,7 @@ function SettingsButton() {
: 'No apps selected'
}
defaultValue={appFilter}
onChange={(data: any) => {
onChange={(data: string[]) => {
setAppFilter(data);
}}
classNames={multiSelectClasses}
@@ -359,7 +361,7 @@ function SettingsButton() {
option: selectClasses.menuSelectOption,
}}
comboboxProps={{ withinPortal: false }}
onChange={(_value, option: any) => {
onChange={(_value, option: ComboboxItem) => {
setAppSort(option.value);
}}
/>
@@ -408,7 +410,7 @@ function SettingsButton() {
<MultiSelect
label='Filter'
data={
categories.toSorted((a: any, b: any) =>
categories.toSorted((a: ComboboxItem, b: ComboboxItem) =>
a.label.localeCompare(b.label),
) ?? []
}
@@ -420,7 +422,7 @@ function SettingsButton() {
: 'No bookmarks selected'
}
defaultValue={bookmarkFilter}
onChange={(data: any) => {
onChange={(data: string[]) => {
setBookmarkFilter(data);
}}
classNames={multiSelectClasses}
@@ -438,7 +440,7 @@ function SettingsButton() {
option: selectClasses.menuSelectOption,
}}
comboboxProps={{ withinPortal: false }}
onChange={(_value, option: any) => {
onChange={(_value, option: ComboboxItem) => {
setBookmarkSort(option.value);
}}
/>

View File

@@ -3,6 +3,8 @@ import {
Box,
Button,
Card,
type ComboboxItem,
type ComboboxLikeRenderOptionInput,
Divider,
Grid,
GridCol,
@@ -179,13 +181,13 @@ const ApplicationSettings = () => {
zIndex: 3000,
withinPortal: false,
}}
onChange={(event: any) => {
onChange={(value: string | null) => {
setNewApplication({
...newApplication,
icon: event,
icon: value ?? '',
});
}}
renderOption={(item: any) => {
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => {
const Icon = allIcons[item.option.value];
return (
<Group>

View File

@@ -2,6 +2,8 @@ import {
ActionIcon,
Button,
Card,
type ComboboxItem,
type ComboboxLikeRenderOptionInput,
Group,
Select,
Stack,
@@ -194,13 +196,13 @@ function DebouncedApplication({
zIndex: 3000,
withinPortal: false,
}}
onChange={(event: any) => {
onChange={(value: string | null) => {
setUpdate({
...app,
icon: event,
icon: value,
});
}}
renderOption={(item: any) => {
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => {
const Icon = allIcons[item.option.value];
return (
<Group>

View File

@@ -10,7 +10,7 @@ import SettingsHeader from '../Shared/SettingsHeader';
import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem';
const BookmarkSettings = () => {
const defaultGroup = {
id: undefined,
id: null,
categoryName: '',
categoryIndex: 0,
filterName: '',

View File

@@ -29,10 +29,14 @@ function SettingsHeader({
setSearchValue,
searchPlaceholder,
}: {
setDragging: any;
setDragging: undefined | ((dragging: boolean) => void);
openModal: () => void;
title: string;
tooltip: any;
tooltip: {
title: string;
highlightList: string[];
description: string;
};
searchValue: string | undefined;
setSearchValue: (searchValue: string) => void;
searchPlaceholder: string | undefined;

View File

@@ -16,7 +16,7 @@ function ThemeCard({
cardTheme: Theme;
handleOpen: (cardTheme: Theme) => void;
allThemes: Theme[];
themePlaylists: any;
themePlaylists: ThemePlaylist[];
}) {
const [hover, setHover] = useState(false);
const [shiftEdit, setShiftEdit] = useState<number>(0);
@@ -274,8 +274,8 @@ function ThemeCard({
onClick={() => {
const themeList = JSON.parse(
themePlaylists?.find(
(t: ThemePlaylist) => t.name === currentThemePlaylist,
).themeList,
(t: ThemePlaylist) => t?.name === currentThemePlaylist,
)?.themeList ?? '[]',
);
const filteredThemes = allThemes.filter((t: Theme) =>
themeList.includes(t.id),

View File

@@ -143,7 +143,7 @@ function ThemeModal({
<Modal.Content>
<Modal.Header style={{ justifyContent: 'center' }}>
<Group pos={'absolute'}>
<Text>Name:</Text>
<Text c={theme.backgroundColor}>Name:</Text>
<TextInput
className={textInputClasses.default}
classNames={textInputClasses}

View File

@@ -32,7 +32,6 @@ function ThemePlaylistCard({
const themeList = JSON.parse(
cardPlaylist.themeList.name === 'Time of Day' ? '[]' : cardPlaylist.themeList,
);
return (
<Group
gap={0}
@@ -253,7 +252,7 @@ function ThemePlaylistCard({
<Stack gap={4}>
{themeList.length > 0 &&
themeList
.sort((a: any, b: any) => (a > b ? 1 : -1))
.sort((a: number, b: number) => (a > b ? 1 : -1))
.map((item: number) => {
return (
<ThemeMiniCard key={item} item={item} allThemes={allThemes} />

View File

@@ -10,7 +10,7 @@ import {
import { useCommonHooks } from 'hooks';
import { useEffect, useState } from 'react';
import { modalClasses, textInputClasses } from 'styles';
import type { Theme } from 'types';
import type { Theme, ThemePlaylist } from 'types';
import ThemeMiniCard from './ThemeMiniCard';
import TimeOfDay from './TimeOfDay';
@@ -19,6 +19,7 @@ function ThemePlaylistModal({
handleClose,
createPlaylist,
selectedPlaylist,
defaultPlaylist,
setSelectedPlaylist,
handleSavePlaylist,
allThemes,
@@ -26,13 +27,15 @@ function ThemePlaylistModal({
opened: boolean;
handleClose: () => void;
createPlaylist: any;
selectedPlaylist: any;
setSelectedPlaylist: (selectedPlaylist: any) => void;
selectedPlaylist: ThemePlaylist;
defaultPlaylist: ThemePlaylist;
setSelectedPlaylist: (selectedPlaylist: ThemePlaylist) => void;
handleSavePlaylist: () => void;
allThemes: Theme[];
}) {
const { theme, isMobile, modalStyle } = useCommonHooks();
const [themeList, setThemeList] = useState<any>('[]');
const [themeList, setThemeList] = useState<any>([]);
useEffect(() => {
if (selectedPlaylist?.themeList) {
setThemeList(JSON.parse(selectedPlaylist?.themeList));
@@ -40,12 +43,8 @@ function ThemePlaylistModal({
}, [selectedPlaylist]);
if (selectedPlaylist?.name === undefined) {
setSelectedPlaylist({
name: 'New Playlist',
themeList: '[]',
});
setSelectedPlaylist(defaultPlaylist);
}
return (
<Modal.Root
size={'50%'}
@@ -64,7 +63,7 @@ function ThemePlaylistModal({
<Modal.Content>
<Modal.Header style={{ justifyContent: 'center' }}>
<Group pos={'absolute'}>
<Text>Name:</Text>
<Text c={theme.backgroundColor}>Name:</Text>
<TextInput
className={textInputClasses.default}
classNames={textInputClasses}
@@ -145,7 +144,7 @@ function ThemePlaylistModal({
onClick={() => {
handleClose();
setThemeList('[]');
setSelectedPlaylist({});
setSelectedPlaylist(defaultPlaylist);
}}
>
Cancel

View File

@@ -18,9 +18,16 @@ function ThemePlaylists() {
const { data: themePlaylists } = useQueryAPI({
endpoint: themePlaylistsEndpoint,
});
const defaultPlaylist = {
id: undefined,
default: 0,
name: 'New Playlist',
themeList: '[]',
};
const { mutateAsync } = useMutationAPI();
const [opened, { open, close }] = useDisclosure(false);
const [selectedPlaylist, setSelectedPlaylist] = useState<ThemePlaylist | undefined>();
const [selectedPlaylist, setSelectedPlaylist] =
useState<ThemePlaylist>(defaultPlaylist);
const { currentThemePlaylist, theme, isMobile } = useCommonHooks();
const [searchValue, setSearchValue] = useState('');
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
@@ -31,7 +38,7 @@ function ThemePlaylists() {
};
const handleClose = () => {
setSelectedPlaylist(undefined);
setSelectedPlaylist(defaultPlaylist);
close();
};
@@ -50,6 +57,7 @@ function ThemePlaylists() {
opened={opened}
handleClose={handleClose}
selectedPlaylist={selectedPlaylist}
defaultPlaylist={defaultPlaylist}
setSelectedPlaylist={setSelectedPlaylist}
handleSavePlaylist={handleSavePlaylist}
allThemes={allThemes}

View File

@@ -1,5 +1,11 @@
import { Group, Select, Text } from '@mantine/core';
import type { Theme } from 'types';
import {
type ComboboxItem,
type ComboboxLikeRenderOptionInput,
Group,
Select,
Text,
} from '@mantine/core';
import type { Theme, ThemePlaylist } from 'types';
function ThemeSelect({
allThemes,
@@ -10,14 +16,15 @@ function ThemeSelect({
timeIndex,
}: {
allThemes: Theme[];
createPlaylist: any;
themeList: any;
selectedPlaylist: any;
index: string;
createPlaylist: (arg0: object) => void;
themeList: Array<string>;
selectedPlaylist: ThemePlaylist;
index: number;
timeIndex: string;
}) {
const theme = allThemes.find((theme: Theme) => `${theme.id}` === themeList[index]);
const theme: Theme | undefined = allThemes.find(
(theme: Theme) => `${theme.id}` === themeList[index],
);
return (
<Group>
<Text w={'100px'}>{timeIndex}</Text>
@@ -34,7 +41,7 @@ function ThemeSelect({
})}
onChange={(data) => {
const newThemeList = themeList;
newThemeList[index] = data;
newThemeList[index] = data as string;
createPlaylist({
method: 'PATCH',
endpoint: 'api/themePlaylists',
@@ -60,8 +67,10 @@ function ThemeSelect({
borderRadius: '8px',
},
}}
renderOption={({ option }: any) => {
const theme = allThemes?.find((theme: Theme) => `${theme.id}` === option.value);
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => {
const theme = allThemes?.find(
(theme: Theme) => `${theme.id}` === item.option.value,
);
return (
<Group
gap={0}
@@ -86,7 +95,10 @@ function ThemeSelect({
borderRadius: '8px',
}}
>
{allThemes.find((theme: Theme) => `${theme.id}` === option.value)?.name}
{
allThemes.find((theme: Theme) => `${theme.id}` === item.option.value)
?.name
}
</Text>
</Group>
);

View File

@@ -5,7 +5,7 @@ import { useEffect, useState } from 'react';
import { FaDice } from 'react-icons/fa';
import { FiChevronRight } from 'react-icons/fi';
import { switchClasses } from 'styles';
import type { Theme } from 'types';
import type { Theme, ThemePlaylist } from 'types';
import SettingsHeader from '../Shared/SettingsHeader';
import ThemeCard from './ThemeCard';
import ThemeModal from './ThemeModal';
@@ -19,9 +19,10 @@ function ThemesSettings() {
const { data: backgroundData, isFetched: isBackgroundFetched } = useQueryAPI({
endpoint: backgroundsEndpoint,
});
const { data: themePlaylists } = useQueryAPI({
const { data: themePlaylistData } = useQueryAPI({
endpoint: 'api/themePlaylists',
});
const [themePlaylists, setThemePlaylists] = useState<ThemePlaylist[]>([]);
const { mutateAsync } = useMutationAPI();
const [opened, { open, close }] = useDisclosure(false);
const [colorId, setColorId] = useState<string>('');
@@ -79,6 +80,13 @@ function ThemesSettings() {
setBackgroundList(['None', ...backgroundData]);
}
}, [backgroundData, isBackgroundFetched]);
useEffect(() => {
if (themePlaylistData) {
setThemePlaylists(themePlaylistData);
}
}, [themePlaylistData]);
return (
<Stack w={'100%'} align='center'>
<ThemeModal

View File

@@ -1,5 +1,5 @@
import { Stack } from '@mantine/core';
import type { Theme } from 'types';
import type { Theme, ThemePlaylist } from 'types';
import ThemeSelect from './ThemeSelect';
function TimeOfDay({
@@ -7,7 +7,12 @@ function TimeOfDay({
themeList,
allThemes,
selectedPlaylist,
}: { createPlaylist: any; themeList: any; allThemes: Theme[]; selectedPlaylist: any }) {
}: {
createPlaylist: () => void;
themeList: Array<string>;
allThemes: Theme[];
selectedPlaylist: ThemePlaylist;
}) {
return (
<Stack>
<ThemeSelect
@@ -15,7 +20,7 @@ function TimeOfDay({
createPlaylist={createPlaylist}
themeList={themeList}
selectedPlaylist={selectedPlaylist}
index='0'
index={0}
timeIndex='00:00 - 05:59'
/>
<ThemeSelect
@@ -23,7 +28,7 @@ function TimeOfDay({
createPlaylist={createPlaylist}
themeList={themeList}
selectedPlaylist={selectedPlaylist}
index='1'
index={1}
timeIndex='06:00 - 11:59'
/>
<ThemeSelect
@@ -31,7 +36,7 @@ function TimeOfDay({
createPlaylist={createPlaylist}
themeList={themeList}
selectedPlaylist={selectedPlaylist}
index='2'
index={2}
timeIndex='12:00 - 17:59'
/>
<ThemeSelect
@@ -39,7 +44,7 @@ function TimeOfDay({
createPlaylist={createPlaylist}
themeList={themeList}
selectedPlaylist={selectedPlaylist}
index='3'
index={3}
timeIndex='18:00 - 23:59'
/>
</Stack>