diff --git a/src/components/FormFooter.tsx b/src/components/FormFooter.tsx new file mode 100644 index 00000000..d9562da8 --- /dev/null +++ b/src/components/FormFooter.tsx @@ -0,0 +1,36 @@ +import type React from 'react'; + +import { FiSave, FiXCircle } from 'react-icons/fi'; + +import { IconButton } from './generic/IconButton'; + +export interface FormFooterProps { + dirty: boolean; + clearAction: () => void; + saveAction: () => void; +} + +export const FormFooter = ({ + dirty, + clearAction, + saveAction, +}: FormFooterProps): JSX.Element => { + return ( +
+ } + disabled={!dirty} + onClick={(): void => { + clearAction(); + }} + /> + { + saveAction(); + }} + icon={} + /> +
+ ); +}; diff --git a/src/components/generic/Card.tsx b/src/components/generic/Card.tsx index 29605856..0ddb194e 100644 --- a/src/components/generic/Card.tsx +++ b/src/components/generic/Card.tsx @@ -3,10 +3,11 @@ import type React from 'react'; type DefaultDivProps = JSX.IntrinsicElements['div']; interface CardProps extends DefaultDivProps { - title: string; - description: string | JSX.Element; + title?: string; + description?: string | JSX.Element; buttons?: JSX.Element; lgPlaceholder?: JSX.Element; + loading?: boolean; } export const Card = ({ @@ -23,15 +24,22 @@ export const Card = ({ className={`flex flex-col flex-auto dark:text-white border-y md:border shadow-md select-none dark:bg-primaryDark border-gray-300 dark:border-transparent md:rounded-3xl ${className}`} {...props} > -
-
-
- {title} + {(title || description) && ( +
+
+ {title && ( +
+ {title} +
+ )} + + {description && ( +
{description}
+ )}
-
{description}
+ {buttons}
- {buttons} -
+ )}
{children} diff --git a/src/components/generic/IconButton.tsx b/src/components/generic/IconButton.tsx index de79e57a..e6e33b55 100644 --- a/src/components/generic/IconButton.tsx +++ b/src/components/generic/IconButton.tsx @@ -4,17 +4,27 @@ type DefaulButtonProps = JSX.IntrinsicElements['button']; export interface IconButtonProps extends DefaulButtonProps { icon: React.ReactNode; + active?: boolean; } export const IconButton = ({ icon, + active, + disabled, ...props }: IconButtonProps): JSX.Element => { return (
+ } >
@@ -76,11 +75,13 @@ export const RangeTest = ({ /> } onClick={(): void => { @@ -38,6 +38,15 @@ export const Channels = ({ }} /> } + rightButton={ + } + active={debug} + onClick={(): void => { + setDebug(!debug); + }} + /> + } footer={ - } - > + } />
{channels.map((channel) => ( diff --git a/src/pages/settings/Connection.tsx b/src/pages/settings/Connection.tsx index cdf7ee91..ca2cd2a4 100644 --- a/src/pages/settings/Connection.tsx +++ b/src/pages/settings/Connection.tsx @@ -2,8 +2,9 @@ import React from 'react'; import { useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { FiCheck, FiMenu, FiSave } from 'react-icons/fi'; +import { FiCheck, FiMenu } from 'react-icons/fi'; +import { FormFooter } from '@app/components/FormFooter'; import { connection, setConnection } from '@app/core/connection'; import { useAppDispatch, useAppSelector } from '@app/hooks/redux'; import { Button } from '@components/generic/Button'; @@ -52,7 +53,7 @@ export const Connection = ({ ); const hostOverride = useAppSelector((state) => state.meshtastic.hostOverride); - const { register, handleSubmit, formState } = useForm<{ + const { register, handleSubmit, formState, reset } = useForm<{ method: connType; }>({ defaultValues: { @@ -121,7 +122,7 @@ export const Connection = ({ } onClick={(): void => { @@ -130,21 +131,14 @@ export const Connection = ({ /> } footer={ - + } > - +
+ + + + + + +
+
+
+ ); +}; diff --git a/src/pages/settings/Power.tsx b/src/pages/settings/Power.tsx new file mode 100644 index 00000000..9391c9c0 --- /dev/null +++ b/src/pages/settings/Power.tsx @@ -0,0 +1,92 @@ +import React from 'react'; + +import { useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { FiCode, FiMenu } from 'react-icons/fi'; +import JSONPretty from 'react-json-pretty'; + +import { FormFooter } from '@app/components/FormFooter'; +import { Select } from '@app/components/generic/form/Select'; +import { connection } from '@app/core/connection'; +import { useAppSelector } from '@app/hooks/redux'; +import { Card } from '@components/generic/Card'; +import { Cover } from '@components/generic/Cover'; +import { Checkbox } from '@components/generic/form/Checkbox'; +import { IconButton } from '@components/generic/IconButton'; +import { PrimaryTemplate } from '@components/templates/PrimaryTemplate'; +import { Protobuf } from '@meshtastic/meshtasticjs'; + +export interface PowerProps { + navOpen?: boolean; + setNavOpen?: React.Dispatch>; +} + +export const Power = ({ navOpen, setNavOpen }: PowerProps): JSX.Element => { + const { t } = useTranslation(); + const radioConfig = useAppSelector((state) => state.meshtastic.preferences); + const [debug, setDebug] = React.useState(false); + + const { register, handleSubmit, formState, reset } = + useForm({ + defaultValues: { + ...radioConfig, + isLowPower: radioConfig.isRouter ? true : radioConfig.isLowPower, + }, + }); + + const onSubmit = handleSubmit((data) => { + void connection.setPreferences(data); + }); + return ( + } + onClick={(): void => { + setNavOpen && setNavOpen(!navOpen); + }} + /> + } + rightButton={ + } + active={debug} + onClick={(): void => { + setDebug(!debug); + }} + /> + } + footer={ + + } + > + + } /> +
+
+ - - -
-
WiFi
- - -
-
Position
- - - - - - -
-
Other
+
diff --git a/src/pages/settings/WiFi.tsx b/src/pages/settings/WiFi.tsx new file mode 100644 index 00000000..05d7e311 --- /dev/null +++ b/src/pages/settings/WiFi.tsx @@ -0,0 +1,93 @@ +import React from 'react'; + +import { useForm, useWatch } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { FiCode, FiMenu } from 'react-icons/fi'; +import JSONPretty from 'react-json-pretty'; + +import { FormFooter } from '@app/components/FormFooter'; +import { Checkbox } from '@app/components/generic/form/Checkbox'; +import { connection } from '@app/core/connection'; +import { useAppSelector } from '@app/hooks/redux'; +import { Card } from '@components/generic/Card'; +import { Cover } from '@components/generic/Cover'; +import { Input } from '@components/generic/form/Input'; +import { IconButton } from '@components/generic/IconButton'; +import { PrimaryTemplate } from '@components/templates/PrimaryTemplate'; +import type { Protobuf } from '@meshtastic/meshtasticjs'; + +export interface WiFiProps { + navOpen?: boolean; + setNavOpen?: React.Dispatch>; +} + +export const WiFi = ({ navOpen, setNavOpen }: WiFiProps): JSX.Element => { + const { t } = useTranslation(); + const radioConfig = useAppSelector((state) => state.meshtastic.preferences); + const [debug, setDebug] = React.useState(false); + + const { register, handleSubmit, formState, reset, control } = + useForm({ + defaultValues: radioConfig, + }); + + const watchWifiApMode = useWatch({ + control, + name: 'wifiApMode', + defaultValue: false, + }); + + const onSubmit = handleSubmit((data) => { + void connection.setPreferences(data); + }); + return ( + } + onClick={(): void => { + setNavOpen && setNavOpen(!navOpen); + }} + /> + } + rightButton={ + } + active={debug} + onClick={(): void => { + setDebug(!debug); + }} + /> + } + footer={ + + } + > + + } /> +
+
+ + + + +
+
+
+ ); +};