More typing and fixes
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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')
|
||||
@@ -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)'}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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'],
|
||||
});
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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: '',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export interface BookmarkGroup {
|
||||
id: number | undefined;
|
||||
id: number | null;
|
||||
categoryName: string;
|
||||
categoryIndex: number;
|
||||
filterName: string;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -5,3 +5,8 @@ export interface SearchHistoryItem {
|
||||
searchTerm: string;
|
||||
dateTimeStamp: string;
|
||||
}
|
||||
|
||||
export interface SearchShortcut {
|
||||
name: string;
|
||||
command: string;
|
||||
}
|
||||
@@ -14,5 +14,5 @@ export interface ThemePlaylist {
|
||||
id: number | undefined;
|
||||
name: string;
|
||||
default: number;
|
||||
themeList: number[];
|
||||
themeList: string;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user