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

@@ -1,8 +1,9 @@
import { Divider, Group } from '@mantine/core';
import { useCommonHooks } from 'hooks';
import type { SearchShortcut } from 'types';
import HintItem from './HintItem';
function HelpSection({ name, items }: { name: string; items: object[] }) {
function HelpSection({ name, items }: { name: string; items: SearchShortcut[] }) {
const { theme } = useCommonHooks();
return (
<>
@@ -30,8 +31,10 @@ function HelpSection({ name, items }: { name: string; items: object[] }) {
}}
>
{items
?.toSorted((a: any, b: any) => (a.command > b.command ? 1 : -1))
.map((item: any) => (
?.toSorted((a: SearchShortcut, b: SearchShortcut) =>
a.command > b.command ? 1 : -1,
)
.map((item: SearchShortcut) => (
<HintItem key={item.command} command={item.command} name={item.name} />
))}
</Group>

View File

@@ -5,7 +5,7 @@ import { useEffect, useState } from 'react';
import { FaLongArrowAltDown, FaLongArrowAltUp, FaWind } from 'react-icons/fa';
import { WiBarometer, WiHumidity, WiSunrise, WiSunset } from 'react-icons/wi';
import { themeIconClasses } from 'styles';
import type { CurrentWeather as CW } from 'types';
import type { CurrentWeather as CW, SunState } from 'types';
import WeatherIcon from './WeatherIcon';
export default function CurrentWeather({ current }: { current: CW }) {
@@ -15,12 +15,12 @@ export default function CurrentWeather({ current }: { current: CW }) {
lon: currentLocation.lon,
});
const [sunStates, setSunStates] = useState<any>([]);
const [sunStates, setSunStates] = useState<SunState[]>([]);
useEffect(() => {
if (sunStateData) {
setSunStates(
sunStateData.results.map((item: any) => {
sunStateData.results.map((item: SunState) => {
return {
date: item.date,
sunrise: item.sunrise,

View File

@@ -1,11 +1,15 @@
import { Group, Stack, Text } from '@mantine/core';
import { useCommonHooks } from 'hooks';
import { textClasses } from 'styles';
import type { ExtendedForecast } from 'types';
import WeatherIcon from './WeatherIcon';
export default function ExtendedForecast({ forecast }: any) {
const day = forecast.slice(2, 14).filter((item: any) => item.isDaytime);
const night = forecast.slice(2, 14).filter((item: any) => !item.isDaytime);
export default function ExtendedForecastCard({
forecast,
}: { forecast: ExtendedForecast[] }) {
const day = forecast.slice(2, 14).filter((item: ExtendedForecast) => item.isDaytime);
const night = forecast.slice(2, 14).filter((item: ExtendedForecast) => !item.isDaytime);
const { isMobile } = useCommonHooks();
return (
<Stack
@@ -30,7 +34,7 @@ export default function ExtendedForecast({ forecast }: any) {
</Text>
</Group>
<Group w={'100%'} align='center' justify='space-between'>
{day.map((item: any, index: number) => {
{day.map((item: ExtendedForecast, index: number) => {
const short = item.shortForecast.includes('And')
? item.shortForecast.substring(0, item.shortForecast.indexOf('And'))
: item.shortForecast.includes('then')

View File

@@ -10,8 +10,11 @@ import {
XAxis,
YAxis,
} from 'recharts';
import type { HourlyForecast } from 'types';
export default function WeatherGraphs({ hourlyForecast }: any) {
export default function WeatherGraphs({
hourlyForecast,
}: { hourlyForecast: HourlyForecast[] }) {
function CustomTooltip({ payload, active }: any) {
if (active) {
return (
@@ -48,7 +51,7 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
<XAxis
type='category'
stroke={'var(--color-text-pri)'}
dataKey={(data: any) => {
dataKey={(data: HourlyForecast) => {
return new Date(data.startTime).toLocaleTimeString('en-US', {
hour: 'numeric',
minute: 'numeric',
@@ -74,7 +77,7 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
unit={'°F'}
type='monotone'
name='Dew Point'
dataKey={(data: any) => {
dataKey={(data: HourlyForecast) => {
return (data.dewpoint.value * 9) / 5 + 32;
}}
stroke={'var(--color-text-acc)'}
@@ -88,7 +91,7 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
<XAxis
type='category'
stroke={'var(--color-text-pri)'}
dataKey={(data: any) => {
dataKey={(data: HourlyForecast) => {
return new Date(data.startTime).toLocaleTimeString('en-US', {
hour: 'numeric',
minute: 'numeric',
@@ -102,7 +105,7 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
unit={'%'}
type='monotone'
name='Precipitation'
dataKey={(data: any) => {
dataKey={(data: HourlyForecast) => {
return data.probabilityOfPrecipitation.value;
}}
stroke={'var(--color-text-pri)'}
@@ -113,7 +116,7 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
unit={'%'}
type='monotone'
name='Humidity'
dataKey={(data: any) => {
dataKey={(data: HourlyForecast) => {
return data.relativeHumidity.value;
}}
stroke={'var(--color-text-acc)'}

View File

@@ -4,9 +4,9 @@ import { modalClasses } from 'styles';
import { useCommonHooks, useWeatherAPI } from 'hooks';
import { useEffect, useState } from 'react';
import type { CurrentWeather as CW, ExtendedForecast as EF } from 'types';
import type { CurrentWeather as CW, ExtendedForecast, HourlyForecast } from 'types';
import CurrentWeather from './CurrentWeather';
import ExtendedForecast from './ExtendedForecast';
import ExtendedForecastCard from './ExtendedForecastCard';
import WeatherGraphs from './WeatherGraphs';
export function WeatherModal({
@@ -19,7 +19,7 @@ export function WeatherModal({
closeWeatherModal,
}: {
current: CW;
extendedForecast: EF[];
extendedForecast: ExtendedForecast[];
weatherModalOpened: boolean;
setSearchValue: (value: string) => void;
setProviderLabel: (label: string) => void;
@@ -33,14 +33,13 @@ export function WeatherModal({
x: currentLocation.x,
y: currentLocation.y,
});
const [hourlyForecast, setHourlyForecast] = useState<any>([]);
const [hourlyForecast, setHourlyForecast] = useState<HourlyForecast[]>([]);
useEffect(() => {
if (hourly) {
setHourlyForecast(hourly.properties.periods.slice(1, 25));
}
}, [hourly]);
return (
<Modal.Root
fullScreen={isMobile}
@@ -79,7 +78,7 @@ export function WeatherModal({
<Stack w={'100%'}>
<CurrentWeather current={current} />
<WeatherGraphs hourlyForecast={hourlyForecast} />
<ExtendedForecast forecast={extendedForecast} />
<ExtendedForecastCard forecast={extendedForecast} />
</Stack>
</Center>
</Modal.Body>

View File

@@ -3,12 +3,12 @@ import { useRef } from 'react';
import { Flip, toast } from 'react-toastify';
const url = `${import.meta.env.PROD ? import.meta.env.VITE_DOMAIN_PROD : import.meta.env.VITE_DOMAIN_DEV}/${import.meta.env.VITE_BASE_URL}`;
const headers = {
const headers: HeadersInit = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Credentials': 'true',
'Sec-Fetch-Mode': 'no-cors',
'Sec-Fetch-Site': 'same-site',
};
@@ -49,7 +49,7 @@ export function useMutationAPI() {
endpoint: string,
body: object | undefined | null,
) => {
const options: any = {
const options: { method: string; headers: HeadersInit | undefined; body: string } = {
method: method,
headers: headers,
body: JSON.stringify(body),

View File

@@ -13,7 +13,7 @@ export function useCommonHooks() {
key: 'theme',
defaultValue: 'blackboard',
});
const [appFilter, setAppFilter] = useLocalStorage<[string]>({
const [appFilter, setAppFilter] = useLocalStorage<string[]>({
key: 'appFilter',
defaultValue: ['All'],
});
@@ -29,7 +29,7 @@ export function useCommonHooks() {
key: 'bookmarkSort',
defaultValue: 'A>Z',
});
const [bookmarkFilter, setBookmarkFilter] = useLocalStorage<[string]>({
const [bookmarkFilter, setBookmarkFilter] = useLocalStorage<string[]>({
key: 'bookmarkFilter',
defaultValue: ['All'],
});

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>

View File

@@ -1,5 +1,5 @@
export interface BookmarkGroup {
id: number | undefined;
id: number | null;
categoryName: string;
categoryIndex: number;
filterName: string;

View File

@@ -1,4 +1,10 @@
export type { CurrentWeather, OutlookWeather, ExtendedForecast } from './weather';
export type {
CurrentWeather,
OutlookWeather,
ExtendedForecast,
HourlyForecast,
SunState,
} from './weather';
export type { Application, AppCategory } from './application';
export type { Bookmark } from './bookmark';
export type { BookmarkGroup } from './bookmarkGroup';
@@ -7,6 +13,6 @@ 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';
export type { SearchHistoryItem, SearchShortcut } from './search';
export type { User } from './user';
export type { Location } from './location';

View File

@@ -5,3 +5,8 @@ export interface SearchHistoryItem {
searchTerm: string;
dateTimeStamp: string;
}
export interface SearchShortcut {
name: string;
command: string;
}

View File

@@ -14,5 +14,5 @@ export interface ThemePlaylist {
id: number | undefined;
name: string;
default: number;
themeList: number[];
themeList: string;
}

View File

@@ -31,3 +31,43 @@ export interface ExtendedForecast {
temperature: number;
temperatureUnit: string;
}
export interface HourlyForecast {
detailedForecast: string;
dewpoint: DewPoint;
endTime: string;
icon: string;
isDaytime: boolean;
name: string;
number: number;
probabilityOfPrecipitation: ProbabilityOfPrecipitation;
relativeHumidity: RelativeHumidity;
shortForecast: string;
startTime: string;
temperature: number;
temperatureTrend: string;
temperatureUnit: string;
windDirection: string;
windSpeed: string;
}
export interface ProbabilityOfPrecipitation {
unitCode: string;
value: number;
}
export interface RelativeHumidity {
unitCode: string;
value: number;
}
export interface DewPoint {
unitCode: string;
value: number;
}
export interface SunState {
date: string;
sunrise: string;
sunset: string;
}