react-hook-form#useWatch TypeScript Examples
The following examples show how to use
react-hook-form#useWatch.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: FormAutosave.tsx From firetable with Apache License 2.0 | 6 votes |
export default function FormAutosave({ control, handleSave }: IAutosaveProps) {
const values = useWatch({ control });
const [debouncedValue] = useDebounce(values, 1000, {
equalityFn: _isEqual,
});
useEffect(() => {
handleSave(debouncedValue);
}, [debouncedValue]);
return null;
}
Example #2
Source File: useVariantFormEvents.ts From calories-in with MIT License | 6 votes |
function useVariantFormEvents({ dietFormStatsTree }: Params) {
const { reset } = useFormContext()
const variantFormFieldId = useWatch({ name: 'variantFormFieldId' })
function getVariantStatsForForFieldId(value: string) {
if (value) {
const stats = dietFormStatsTree.subtrees.find(({ id }) => id === value)
if (!stats) {
throw new Error()
}
return stats.stats
}
return dietFormStatsTree.avg as Stats
}
const variantStats = getVariantStatsForForFieldId(variantFormFieldId)
function onVariantFormFieldIdChange(value: string) {
const variantStats = getVariantStatsForForFieldId(value)
const newVaraintsDetailsForm = getVariantsDetailsForm(value, variantStats)
reset(newVaraintsDetailsForm)
}
return { onVariantFormFieldIdChange, variantStats }
}
Example #3
Source File: deploy-form.tsx From sdk with MIT License | 6 votes |
export function DeployForm({ form }: IDeployFormProps) {
const connection = useContext(ConnectorContext)
const blockchain = useWatch({
control: form.control,
name: "blockchain",
}) ?? connection.sdk?.wallet?.blockchain
switch (blockchain) {
case BlockchainGroup.ETHEREUM:
return <EthereumDeployForm form={form}/>
case BlockchainGroup.TEZOS:
return <TezosDeployForm form={form}/>
case BlockchainGroup.SOLANA:
return <SolanaDeployForm form={form}/>
default:
return <Box sx={{my: 2}}>Deploy not available for selected blockchain</Box>
}
}
Example #4
Source File: ShowFractional.tsx From rabet-extension with GNU General Public License v3.0 | 6 votes |
ShowFractional = ({
control,
isRotateActive,
}: ShowFractionalProps) => {
const formValues = useWatch({ control });
const values = {
value1: formValues.from,
asset1: formValues.asset1,
value2: formValues.to,
asset2: formValues.asset2,
};
if (isRotateActive) {
values.value1 = formValues.to;
values.asset1 = formValues.asset2;
values.value2 = formValues.from;
values.asset2 = formValues.asset1;
}
const denominator = new BN(values.value2)
.div(new BN(values.value1))
.toFixed(5);
return (
<span className="text-sm text-primary-dark">
1 {values.asset1.asset_code || 'XLM'} = {denominator.toString()}{' '}
{values.asset2.asset_code || 'XLM'}
</span>
);
}
Example #5
Source File: FormContainer.stories.tsx From react-hook-form-mui with MIT License | 6 votes |
SubComponent = () => {
const [name, email] = useWatch({
name: ['name', 'email']
})
console.log(name, email)
return (
<>
<Button type={'submit'} color={'primary'} disabled={!(name && email)}>Submit</Button>
</>
)
}
Example #6
Source File: SideDrawerField.tsx From firetable with Apache License 2.0 | 6 votes |
export default function SubTable({
column,
control,
docRef,
}: ISideDrawerFieldProps) {
const fieldClasses = useFieldStyles();
const row = useWatch({ control });
const { documentCount, label, subTablePath } = useSubTableData(
column,
row,
docRef
);
return (
<Grid container wrap="nowrap">
<div className={fieldClasses.root}>
{documentCount} {column.name}: {label}
</div>
<IconButton
component={Link}
to={subTablePath}
style={{ width: 56, marginLeft: 16 }}
disabled={!subTablePath}
>
<LaunchIcon />
</IconButton>
</Grid>
);
}
Example #7
Source File: PasswordRepeatElement.tsx From react-hook-form-mui with MIT License | 6 votes |
export default function PasswordRepeatElement(props: PasswordRepeatElementProps) {
const pwValue = useWatch({
name: props.passwordFieldName,
control: props.control,
defaultValue: ''
})
return (
<PasswordElement {...props}
validation={{
validate: (value: string) => {
return value === pwValue || 'Password should match'
}
}}
/>
)
}
Example #8
Source File: Autosave.tsx From firetable with Apache License 2.0 | 5 votes |
export default function Autosave({
control,
docRef,
row,
reset,
dirtyFields,
}: IAutosaveProps) {
const { tableState, updateCell } = useFiretableContext();
const values = useWatch({ control });
const [debouncedValue] = useDebounce(getEditables(values, tableState), 1000, {
equalityFn: _isEqual,
});
useEffect(() => {
if (!row || !row.ref) return;
if (row.ref.id !== docRef.id) return;
if (!updateCell) return;
// Get only fields that have had their value updated by the user
const updatedValues = _pickBy(
_pickBy(debouncedValue, (_, key) => dirtyFields[key]),
(value, key) => !_isEqual(value, row[key])
);
console.log(debouncedValue, row);
console.log(updatedValues, dirtyFields);
if (Object.keys(updatedValues).length === 0) return;
// Update the document
Object.entries(updatedValues).forEach(([key, value]) =>
updateCell(
row.ref,
key,
value,
// After the cell is updated, set this field to be not dirty
// so it doesn’t get updated again when a different field in the form
// is updated + make sure the new value is kept after reset
() => reset({ ...values, [key]: value })
)
);
}, [debouncedValue]);
return null;
}
Example #9
Source File: Address.tsx From UsTaxes with GNU Affero General Public License v3.0 | 5 votes |
export default function AddressFields(props: AddressProps): ReactElement {
const {
autofocus,
checkboxText = 'Check if you have a foreign address',
allowForeignCountry = true
} = props
const { control } = useFormContext<{ isForeignCountry: boolean }>()
const isForeignCountry = useWatch({
name: 'isForeignCountry',
control
})
const csz: ReactElement = (() => {
if (!allowForeignCountry || !isForeignCountry) {
return (
<>
<USStateDropDown
label="State"
name="address.state"
required={!isForeignCountry}
/>
<LabeledInput
label="Zip"
name="address.zip"
patternConfig={Patterns.zip}
required={!isForeignCountry}
/>
</>
)
}
return (
<>
<LabeledInput
label="Province"
name="address.province"
required={isForeignCountry}
/>
<LabeledInput
name="address.postalCode"
label="Postal Code"
required={isForeignCountry}
/>
<CountryDropDown
name="address.foreignCountry"
label="Country"
required={isForeignCountry}
/>
</>
)
})()
return (
<>
<LabeledInput
autofocus={autofocus}
label="Address"
name="address.address"
required={true}
/>
<LabeledInput label="Unit No" name="address.aptNo" required={false} />
<LabeledInput
label="City"
name="address.city"
patternConfig={Patterns.name}
/>
{(() => {
if (allowForeignCountry) {
return (
<LabeledCheckbox label={checkboxText} name="isForeignCountry" />
)
}
})()}
{csz}
</>
)
}
Example #10
Source File: SideDrawerField.tsx From firetable with Apache License 2.0 | 5 votes |
export default function Action({
column,
control,
docRef,
disabled,
}: ISideDrawerFieldProps) {
const classes = useStyles();
const fieldClasses = useFieldStyles();
const row = useWatch({ control });
return (
<Controller
control={control}
name={column.key}
render={({ onChange, value }) => {
const hasRan = value && value.status;
return (
<Grid container alignItems="center" wrap="nowrap" spacing={2}>
<Grid item xs className={classes.labelGridItem}>
<div className={fieldClasses.root}>
<Typography variant="body1" className={classes.label}>
{hasRan && isUrl(value.status) ? (
<Link
href={value.status}
target="_blank"
rel="noopener noreferrer"
variant="body2"
underline="always"
>
{value.status}
</Link>
) : hasRan ? (
value.status
) : (
sanitiseCallableName(column.key)
)}
</Typography>
</div>
</Grid>
<Grid item>
<ActionFab
row={{ ...row, ref: docRef }}
column={{ config: column.config, key: column.key }}
onSubmit={onChange}
value={value}
disabled={disabled}
/>
</Grid>
</Grid>
);
}}
/>
);
}
Example #11
Source File: SideDrawerField.tsx From firetable with Apache License 2.0 | 5 votes |
export default function Percentage({
control,
column,
disabled,
}: ISideDrawerFieldProps) {
const value: number | undefined = useWatch({ control, name: column.key });
const classes = useStyles({ value });
return (
<Controller
control={control}
name={column.key}
render={({ onChange, onBlur, value }) => {
const handleChange = (e) => onChange(Number(e.target.value) / 100);
return (
<TextField
variant="filled"
fullWidth
margin="none"
placeholder={column.name}
onChange={handleChange}
onBlur={onBlur}
value={typeof value === "number" ? value * 100 : value}
id={`sidedrawer-field-${column.key}`}
label=""
hiddenLabel
disabled={disabled}
type="number"
InputProps={{
endAdornment: "%",
classes: {
root: classes.resultColor,
underline: classes.underline,
},
}}
/>
);
}}
/>
);
}
Example #12
Source File: StoreForward.tsx From meshtastic-web with GNU General Public License v3.0 | 5 votes |
StoreForwardSettingsPanel = (): JSX.Element => {
const [loading, setLoading] = useState(false);
const storeForwardConfig = useAppSelector(
(state) => state.meshtastic.radio.moduleConfig.storeForward,
);
const { register, handleSubmit, formState, reset, control } =
useForm<Protobuf.ModuleConfig_StoreForwardConfig>({
defaultValues: storeForwardConfig,
});
useEffect(() => {
reset(storeForwardConfig);
}, [reset, storeForwardConfig]);
const onSubmit = handleSubmit(async (data) => {
setLoading(true);
await connection.setModuleConfig(
{
payloadVariant: {
oneofKind: 'storeForward',
storeForward: data,
},
},
async (): Promise<void> => {
reset({ ...data });
setLoading(false);
await Promise.resolve();
},
);
});
const moduleEnabled = useWatch({
control,
name: 'enabled',
defaultValue: false,
});
return (
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
<Checkbox label="Module Enabled" {...register('enabled')} />
<Checkbox
label="Heartbeat Enabled"
disabled={!moduleEnabled}
{...register('heartbeat')}
/>
<Input
type="number"
label="Number of records"
suffix="Records"
disabled={!moduleEnabled}
{...register('records', {
valueAsNumber: true,
})}
/>
<Input
type="number"
label="History return max"
disabled={!moduleEnabled}
{...register('historyReturnMax', {
valueAsNumber: true,
})}
/>
<Input
type="number"
label="History return window"
disabled={!moduleEnabled}
{...register('historyReturnWindow', {
valueAsNumber: true,
})}
/>
</Form>
);
}
Example #13
Source File: RangeTest.tsx From meshtastic-web with GNU General Public License v3.0 | 5 votes |
RangeTestSettingsPanel = (): JSX.Element => {
const [loading, setLoading] = useState(false);
const rangeTestConfig = useAppSelector(
(state) => state.meshtastic.radio.moduleConfig.rangeTest,
);
const { register, handleSubmit, formState, reset, control } =
useForm<Protobuf.ModuleConfig_RangeTestConfig>({
defaultValues: rangeTestConfig,
});
useEffect(() => {
reset(rangeTestConfig);
}, [reset, rangeTestConfig]);
const onSubmit = handleSubmit(async (data) => {
setLoading(true);
await connection.setModuleConfig(
{
payloadVariant: {
oneofKind: 'rangeTest',
rangeTest: data,
},
},
async (): Promise<void> => {
reset({ ...data });
setLoading(false);
await Promise.resolve();
},
);
});
const moduleEnabled = useWatch({
control,
name: 'enabled',
defaultValue: false,
});
return (
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
<Checkbox label="Module Enabled" {...register('enabled')} />
<Input
type="number"
label="Message Interval"
disabled={!moduleEnabled}
suffix="Seconds"
{...register('sender', {
valueAsNumber: true,
})}
/>
<Checkbox
label="Save CSV to storage"
disabled={!moduleEnabled}
{...register('save')}
/>
</Form>
);
}
Example #14
Source File: MQTT.tsx From meshtastic-web with GNU General Public License v3.0 | 5 votes |
MQTT = (): JSX.Element => {
const mqttConfig = useAppSelector(
(state) => state.meshtastic.radio.moduleConfig.mqtt,
);
const [loading, setLoading] = useState(false);
const { register, handleSubmit, formState, reset, control } =
useForm<Protobuf.ModuleConfig_MQTTConfig>({
defaultValues: mqttConfig,
});
const moduleEnabled = useWatch({
control,
name: 'disabled',
defaultValue: false,
});
useEffect(() => {
reset(mqttConfig);
}, [reset, mqttConfig]);
const onSubmit = handleSubmit((data) => {
setLoading(true);
void connection.setModuleConfig(
{
payloadVariant: {
oneofKind: 'mqtt',
mqtt: data,
},
},
async () => {
reset({ ...data });
setLoading(false);
await Promise.resolve();
},
);
});
return (
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
<Checkbox label="Module Disabled" {...register('disabled')} />
<Input
label="MQTT Server Address"
disabled={moduleEnabled}
{...register('address')}
/>
<Input
label="MQTT Username"
disabled={moduleEnabled}
{...register('username')}
/>
<Input
label="MQTT Password"
type="password"
autoComplete="off"
disabled={moduleEnabled}
{...register('password')}
/>
<Checkbox
label="Encryption Enabled"
disabled={moduleEnabled}
{...register('encryptionEnabled')}
/>
</Form>
);
}
Example #15
Source File: ExternalNotifications.tsx From meshtastic-web with GNU General Public License v3.0 | 5 votes |
ExternalNotificationsSettingsPlanel = (): JSX.Element => {
const [loading, setLoading] = useState(false);
const extNotificationConfig = useAppSelector(
(state) => state.meshtastic.radio.moduleConfig.extNotification,
);
const { register, handleSubmit, formState, reset, control } =
useForm<Protobuf.ModuleConfig_ExternalNotificationConfig>({
defaultValues: extNotificationConfig,
});
useEffect(() => {
reset(extNotificationConfig);
}, [reset, extNotificationConfig]);
const onSubmit = handleSubmit(async (data) => {
setLoading(true);
await connection.setModuleConfig(
{
payloadVariant: {
oneofKind: 'externalNotification',
externalNotification: data,
},
},
async (): Promise<void> => {
reset({ ...data });
setLoading(false);
await Promise.resolve();
},
);
});
const moduleEnabled = useWatch({
control,
name: 'enabled',
defaultValue: false,
});
return (
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
<Checkbox label="Module Enabled" {...register('enabled')} />
<Input
type="number"
label="Output MS"
suffix="ms"
disabled={!moduleEnabled}
{...register('outputMs', {
valueAsNumber: true,
})}
/>
<Input
type="number"
label="Output"
disabled={!moduleEnabled}
{...register('output', {
valueAsNumber: true,
})}
/>
<Checkbox
label="Active"
disabled={!moduleEnabled}
{...register('active')}
/>
<Checkbox
label="Message"
disabled={!moduleEnabled}
{...register('alertMessage')}
/>
<Checkbox
label="Bell"
disabled={!moduleEnabled}
{...register('alertBell')}
/>
</Form>
);
}
Example #16
Source File: WiFi.tsx From meshtastic-web with GNU General Public License v3.0 | 5 votes |
WiFi = (): JSX.Element => {
const wifiConfig = useAppSelector(
(state) => state.meshtastic.radio.config.wifi,
);
const [loading, setLoading] = useState(false);
const { register, handleSubmit, formState, reset, control } =
useForm<Protobuf.Config_WiFiConfig>({
defaultValues: wifiConfig,
});
const WifiApMode = useWatch({
control,
name: 'apMode',
defaultValue: false,
});
useEffect(() => {
reset(wifiConfig);
}, [reset, wifiConfig]);
const onSubmit = handleSubmit((data) => {
setLoading(true);
void connection.setConfig(
{
payloadVariant: {
oneofKind: 'wifi',
wifi: data,
},
},
async () => {
reset({ ...data });
setLoading(false);
await Promise.resolve();
},
);
});
return (
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
<Checkbox label="Enable WiFi AP" {...register('apMode')} />
<Input label="WiFi SSID" disabled={WifiApMode} {...register('ssid')} />
<Input
type="password"
autoComplete="off"
label="WiFi PSK"
disabled={WifiApMode}
{...register('psk')}
/>
</Form>
);
}
Example #17
Source File: HTTP.tsx From meshtastic-web with GNU General Public License v3.0 | 5 votes |
HTTP = ({ connecting }: HTTPProps): JSX.Element => {
const dispatch = useAppDispatch();
const { register, handleSubmit, control } = useForm<{
ipSource: 'local' | 'remote';
ip?: string;
tls: boolean;
}>({
defaultValues: {
ipSource: 'local',
ip: connectionUrl,
tls: false,
},
});
const watchIpSource = useWatch({
control,
name: 'ipSource',
defaultValue: 'local',
});
const onSubmit = handleSubmit(async (data) => {
if (data.ip) {
localStorage.setItem('connectionUrl', data.ip);
}
dispatch(
setConnectionParams({
type: connType.HTTP,
params: {
address: data.ip ?? connectionUrl,
tls: data.tls,
fetchInterval: 2000,
},
}),
);
await setConnection(connType.HTTP);
});
return (
<form onSubmit={onSubmit}>
<Select
label="Host Source"
options={[
{
name: 'Local',
value: 'local',
},
{
name: 'Remote',
value: 'remote',
},
]}
disabled={connecting}
{...register('ipSource')}
/>
{watchIpSource === 'local' ? (
<Input label="Host" value={connectionUrl} disabled />
) : (
<Input label="Host" disabled={connecting} {...register('ip')} />
)}
<Checkbox label="Use TLS?" disabled={connecting} {...register('tls')} />
<Button
className="mt-2 ml-auto"
onClick={async (): Promise<void> => {
if (connecting) {
await connection.disconnect();
} else {
await onSubmit();
}
}}
border
>
{connecting ? 'Disconnect' : 'Connect'}
</Button>
</form>
);
}
Example #18
Source File: usePricesFieldArray.ts From admin with MIT License | 5 votes |
usePricesFieldArray = <TKeyName extends string = "id">(
currencyCodes: string[],
{ control, name, keyName }: UseFieldArrayOptions<TKeyName>,
options: UsePricesFieldArrayOptions = {
defaultAmount: 1000,
defaultCurrencyCode: "usd",
}
) => {
const { defaultAmount, defaultCurrencyCode } = options
const { fields, append, remove } = useFieldArray<PriceFormValue, TKeyName>({
control,
name,
keyName,
})
const watchedFields = useWatch({
control,
name,
defaultValue: fields,
})
const selectedCurrencies = watchedFields.map(
(field) => field?.price?.currency_code
)
const availableCurrencies = currencyCodes?.filter(
(currency) => !selectedCurrencies.includes(currency)
)
const controlledFields = fields.map((field, index) => {
return {
...field,
...watchedFields[index],
}
})
const appendPrice = () => {
let newCurrency = availableCurrencies[0]
if (!selectedCurrencies.includes(defaultCurrencyCode)) {
newCurrency = defaultCurrencyCode
}
append({
price: { currency_code: newCurrency, amount: defaultAmount },
})
}
const deletePrice = (index) => {
return () => {
remove(index)
}
}
return {
fields: controlledFields,
appendPrice,
deletePrice,
availableCurrencies,
selectedCurrencies,
} as const
}
Example #19
Source File: promotion-type.tsx From admin with MIT License | 5 votes |
PromotionType = () => {
const { control } = useDiscountForm()
const regions = useWatch({
control,
name: "regions",
})
return (
<Controller
name="rule.type"
control={control}
rules={{ required: true }}
render={({ onChange, value }) => {
return (
<RadioGroup.Root
value={value}
onValueChange={onChange}
className={clsx("flex items-center gap-base mt-base px-1")}
>
<RadioGroup.Item
value={DiscountRuleType.PERCENTAGE}
className="flex-1"
label="Percentage"
description={"Discount applied in %"}
/>
<RadioGroup.Item
value={DiscountRuleType.FIXED}
className="flex-1"
label="Fixed amount"
description={"Discount in whole numbers"}
disabled={Array.isArray(regions) && regions.length > 1}
disabledTooltip="You can only select one valid region if you want to use the fixed amount type"
/>
<RadioGroup.Item
value={DiscountRuleType.FREE_SHIPPING}
className="flex-1"
label="Free shipping"
description={"Override delivery amount"}
/>
</RadioGroup.Root>
)
}}
/>
)
}
Example #20
Source File: index.tsx From admin with MIT License | 5 votes |
ControlledCheckbox = ({
control,
name,
id,
index,
value,
...props
}: ControlledCheckboxProps) => {
const variants = useWatch<string[]>({
control,
name,
})
return (
<Controller
control={control}
name={name}
render={(field) => {
return (
<Checkbox
className="shrink-0 inter-small-regular"
{...props}
{...field}
checked={variants?.some((variant) => variant === value)}
onChange={(e) => {
// copy field value
const valueCopy = [...(variants || [])] as any[]
// update checkbox value
valueCopy[index] = e.target.checked ? id : null
// update field value
field.onChange(valueCopy)
}}
/>
)
}}
/>
)
}
Example #21
Source File: CannedMessage.tsx From meshtastic-web with GNU General Public License v3.0 | 4 votes |
CannedMessage = (): JSX.Element => {
const cannedMessageConfig = useAppSelector(
(state) => state.meshtastic.radio.moduleConfig.cannedMessage,
);
const [loading, setLoading] = useState(false);
const { register, handleSubmit, formState, reset, control } =
useForm<Protobuf.ModuleConfig_CannedMessageConfig>({
defaultValues: cannedMessageConfig,
});
const moduleEnabled = useWatch({
control,
name: 'rotary1Enabled',
defaultValue: false,
});
useEffect(() => {
reset(cannedMessageConfig);
}, [reset, cannedMessageConfig]);
const onSubmit = handleSubmit((data) => {
setLoading(true);
void connection.setModuleConfig(
{
payloadVariant: {
oneofKind: 'cannedMessage',
cannedMessage: data,
},
},
async () => {
reset({ ...data });
setLoading(false);
await Promise.resolve();
},
);
});
return (
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
<Checkbox label="Module Enabled" {...register('enabled')} />
<Checkbox
label="Rotary Encoder #1 Enabled"
{...register('rotary1Enabled')}
/>
<Input
label="Encoder Pin A"
type="number"
disabled={moduleEnabled}
{...register('inputbrokerPinA', { valueAsNumber: true })}
/>
<Input
label="Encoder Pin B"
type="number"
disabled={moduleEnabled}
{...register('inputbrokerPinB', { valueAsNumber: true })}
/>
<Input
label="Endoer Pin Press"
type="number"
disabled={moduleEnabled}
{...register('inputbrokerPinPress', { valueAsNumber: true })}
/>
<Select
label="Clockwise event"
disabled={moduleEnabled}
optionsEnum={Protobuf.ModuleConfig_CannedMessageConfig_InputEventChar}
{...register('inputbrokerEventCw', { valueAsNumber: true })}
/>
<Select
label="Counter Clockwise event"
disabled={moduleEnabled}
optionsEnum={Protobuf.ModuleConfig_CannedMessageConfig_InputEventChar}
{...register('inputbrokerEventCcw', { valueAsNumber: true })}
/>
<Select
label="Press event"
disabled={moduleEnabled}
optionsEnum={Protobuf.ModuleConfig_CannedMessageConfig_InputEventChar}
{...register('inputbrokerEventPress', { valueAsNumber: true })}
/>
<Checkbox label="Up Down enabled" {...register('updown1Enabled')} />
<Input
label="Allow Input Source"
disabled={moduleEnabled}
{...register('allowInputSource')}
/>
<Checkbox label="Send Bell" {...register('sendBell')} />
</Form>
);
}
Example #22
Source File: pricing-form-context.tsx From admin with MIT License | 4 votes |
PriceListFormProvider: React.FC<FormProviderProps> = ({
priceList = defaultState,
children,
}) => {
const [configFields, setConfigFields] = useState<
Record<ConfigurationField, unknown>
>({
customer_groups: priceList.customer_groups,
ends_at: priceList.ends_at,
starts_at: priceList.starts_at,
})
const methods = useForm<PriceListFormValues>({
defaultValues: priceList,
})
const [prices, setPrices] = useState<CreatePriceListPricesFormValues | null>(
null
)
const currentStartsAt = useWatch({
name: "starts_at",
control: methods.control,
})
const currentEndsAt = useWatch({
name: "ends_at",
control: methods.control,
})
const currentCustomerGroups = useWatch({
name: "customer_groups",
control: methods.control,
})
const disableConfiguration = (configField: ConfigurationField) => {
let configToSave: unknown | null = null
switch (configField) {
case ConfigurationField.CUSTOMER_GROUPS:
configToSave = currentCustomerGroups
break
case ConfigurationField.STARTS_AT:
configToSave = currentStartsAt
break
case ConfigurationField.ENDS_AT:
configToSave = currentEndsAt
break
}
// we save the configuration field value to the state, so that if the user re-enables the field we can populate it with the previous value
setConfigFields({
...configFields,
[configField]: configToSave,
})
// use timeout to avoid flashing default value
setTimeout(() => methods.setValue(configField, null), 300)
}
const enableConfiguration = (configField: ConfigurationField) => {
// we get the configuration field value from the state, so that if the user re-enables the field we can populate it with the previous value
if (configFields[configField]) {
methods.setValue(configField, configFields[configField])
} else {
// if the configuration field value is null, we set a default value
switch (configField) {
case ConfigurationField.STARTS_AT:
methods.setValue(configField, new Date())
break
case ConfigurationField.ENDS_AT:
methods.setValue(configField, weekFromNow())
break
case ConfigurationField.CUSTOMER_GROUPS:
methods.setValue(configField, [])
break
}
}
}
const handleConfigurationSwitch = (values: string[]) => {
for (const key of Object.keys(configFields)) {
if (values.includes(key)) {
enableConfiguration(key as ConfigurationField)
} else {
disableConfiguration(key as ConfigurationField)
}
}
}
const handleSubmit = (submitHandler) => {
return methods.handleSubmit((values) => {
submitHandler({ ...values, prices })
})
}
return (
<FormProvider {...methods}>
<PriceListFormContext.Provider
value={{
configFields,
handleConfigurationSwitch,
prices,
handleSubmit,
setPrices,
}}
>
{children}
</PriceListFormContext.Provider>
</FormProvider>
)
}
Example #23
Source File: Serial.tsx From meshtastic-web with GNU General Public License v3.0 | 4 votes |
SerialSettingsPanel = (): JSX.Element => {
const [loading, setLoading] = useState(false);
const serialConfig = useAppSelector(
(state) => state.meshtastic.radio.moduleConfig.serial,
);
const { register, handleSubmit, formState, reset, control } =
useForm<Protobuf.ModuleConfig_SerialConfig>({
defaultValues: serialConfig,
});
useEffect(() => {
reset(serialConfig);
}, [reset, serialConfig]);
const onSubmit = handleSubmit(async (data) => {
setLoading(true);
await connection.setModuleConfig(
{
payloadVariant: {
oneofKind: 'serial',
serial: data,
},
},
async (): Promise<void> => {
reset({ ...data });
setLoading(false);
await Promise.resolve();
},
);
});
const moduleEnabled = useWatch({
control,
name: 'enabled',
defaultValue: false,
});
return (
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
<Checkbox label="Module Enabled" {...register('enabled')} />
<Checkbox label="Echo" disabled={!moduleEnabled} {...register('echo')} />
<Input
type="number"
label="RX"
disabled={!moduleEnabled}
{...register('rxd', {
valueAsNumber: true,
})}
/>
<Input
type="number"
label="TX Pin"
disabled={!moduleEnabled}
{...register('txd', {
valueAsNumber: true,
})}
/>
<Input
type="number"
label="Baud Rate"
disabled={!moduleEnabled}
{...register('baud', {
valueAsNumber: true,
})}
/>
<Input
type="number"
label="Timeout"
disabled={!moduleEnabled}
{...register('timeout', {
valueAsNumber: true,
})}
/>
<Input
type="number"
label="Mode"
disabled={!moduleEnabled}
{...register('mode', {
valueAsNumber: true,
})}
/>
</Form>
);
}
Example #24
Source File: index.tsx From rabet-extension with GNU General Public License v3.0 | 4 votes |
SwapDetails = ({
path,
values,
control,
minimumReceived,
}: SwapDetailsProps) => {
const [marketPrice, setMarketPrice] = useState<BigNumber | string>(
'',
);
let formValues = values;
if (control) {
formValues = useWatch({ control });
}
useEffect(() => {
calculatePriceImpact(formValues.asset1, formValues.asset2).then(
(result) => {
setMarketPrice(result);
},
);
}, [formValues]);
const priceImpact = new BN(1)
.minus(
new BN(minimumReceived).div(
new BN(marketPrice).times(formValues.from),
),
)
.times(100);
let finalPriceImpact = priceImpact.toFixed(2);
if (priceImpact.isNaN() || !priceImpact.isFinite()) {
finalPriceImpact = '0';
}
if (priceImpact.isLessThan(0)) {
finalPriceImpact = '0';
}
if (priceImpact.isLessThan(0.1)) {
finalPriceImpact = '<0.01';
}
const assetCode = (asset) =>
asset.asset_type === 'native' ? 'XLM' : asset.asset_code;
return (
<>
<S.Box>
<S.BoxTitle>Path</S.BoxTitle>
<S.Path>
{path.map((p, index) => (
<div key={assetCode(p)} className="flex items-center">
{assetCode(p)}
{index !== path.length - 1 && (
<div className="mx-[5px]">
<AngleRight />
</div>
)}
</div>
))}
</S.Path>
</S.Box>
<S.Box>
<S.BoxTitle>Price impact</S.BoxTitle>
<S.BoxValue
className="up"
color={priceImpactColor(finalPriceImpact)}
>
{finalPriceImpact.toString()}%
</S.BoxValue>
</S.Box>
<S.Box>
<S.BoxTitle>Minimum received</S.BoxTitle>
<div>
{minimumReceived ? (
<>
{formatBalance(minimumReceived.toString())}{' '}
{formValues.asset2.asset_code || 'XLM'}
</>
) : (
<p>Asset</p>
)}
</div>
</S.Box>
</>
);
}
Example #25
Source File: general.tsx From admin with MIT License | 4 votes |
General: React.FC<GeneralProps> = ({ discount }) => {
const initialCurrency = discount?.regions?.[0].currency_code || undefined
const [fixedRegionCurrency, setFixedRegionCurrency] = useState<
string | undefined
>(initialCurrency)
const { regions: opts } = useAdminRegions()
const { register, control, type } = useDiscountForm()
const regions = useWatch({
control,
name: "regions",
})
useEffect(() => {
if (type === "fixed" && regions) {
let id: string
if (Array.isArray(regions) && regions.length) {
id = regions[0].value
} else {
id = ((regions as unknown) as { label: string; value: string }).value // if you change from fixed to percentage, unselect and select a region, and then change back to fixed it is possible to make useForm set regions to an object instead of an array
}
const reg = opts?.find((r) => r.id === id)
if (reg) {
setFixedRegionCurrency(reg.currency_code)
}
}
}, [type, opts, regions])
const regionOptions = useMemo(() => {
return opts?.map((r) => ({ value: r.id, label: r.name })) || []
}, [opts])
const [render, setRender] = useState(false)
useEffect(() => {
setTimeout(() => setRender(true), 100)
}, [])
return (
<div className="pt-5">
{render && (
<>
<Controller
name="regions"
control={control}
rules={{
required: "Atleast one region is required",
validate: (value) =>
Array.isArray(value) ? value.length > 0 : !!value,
}}
render={({ onChange, value }) => {
return (
<Select
value={value || null}
onChange={(value) => {
onChange(type === "fixed" ? [value] : value)
}}
label="Choose valid regions"
isMultiSelect={type !== "fixed"}
hasSelectAll={type !== "fixed"}
enableSearch
required
options={regionOptions}
/>
)
}}
/>
<div className="flex gap-x-base gap-y-base my-base">
<InputField
label="Code"
className="flex-1"
placeholder="SUMMERSALE10"
required
name="code"
ref={register({ required: "Code is required" })}
/>
{type !== "free_shipping" && (
<>
{type === "fixed" ? (
<div className="flex-1">
<CurrencyInput
size="small"
currentCurrency={fixedRegionCurrency}
readOnly
hideCurrency
>
<Controller
name="rule.value"
control={control}
rules={{
required: "Amount is required",
min: 1,
}}
render={({ value, onChange }) => {
return (
<CurrencyInput.AmountInput
label={"Amount"}
required
amount={value}
onChange={onChange}
/>
)
}}
/>
</CurrencyInput>
</div>
) : (
<div className="flex-1">
<InputField
label="Percentage"
min={0}
required
type="number"
placeholder="10"
prefix={"%"}
name="rule.value"
ref={register({
required: true,
valueAsNumber: true,
})}
/>
</div>
)}
</>
)}
</div>
<div className="text-grey-50 inter-small-regular flex flex-col mb-6">
<span>
The code your customers will enter during checkout. This will
appear on your customer’s invoice.
</span>
<span>Uppercase letters and numbers only.</span>
</div>
<Textarea
label="Description"
required
placeholder="Summer Sale 2022"
rows={1}
name="rule.description"
ref={register({
required: true,
})}
/>
<div className="mt-xlarge flex items-center">
<Controller
name="is_dynamic"
control={control}
render={({ onChange, value }) => {
return (
<Checkbox
label="This is a template discount"
name="is_dynamic"
id="is_dynamic"
checked={value}
onChange={(e) => onChange(e.target.checked)}
/>
)
}}
/>
<IconTooltip
content={
"Template discounts allow you to define a set of rules that can be used across a group of discounts. This is useful in campaigns that should generate unique codes for each user, but where the rules for all unique codes should be the same."
}
/>
</div>
</>
)}
</div>
)
}
Example #26
Source File: index.tsx From rabet-extension with GNU General Public License v3.0 | 4 votes |
BasicSwap = ({ usage }: AppProps) => {
const navigate = useNavigate();
const account = useActiveAccount();
const [assets] = useState(() => {
const accountAssets = account.assets || [];
const assetsPlusDefaultAssets = combineAssets(
accountAssets,
defaultAssets,
);
return assetsPlusDefaultAssets;
});
const [path, setPath] = useState([]);
const [loading, setLoading] = useState(false);
const [showSwapInfo, setShowSwapInfo] = useState(false);
const [minimumReceived, setMinimumReceived] = useState(0);
const [isRotateActive, setIsRotateActive] = useState(false);
const [shouldRotate, setShouldRotate] = useState(false);
const {
reset,
trigger,
control,
setValue,
getValues,
handleSubmit,
clearErrors,
formState: { errors, isValid, isValidating },
} = useForm({
mode: 'onChange',
defaultValues: {
to: '',
from: '',
asset1: assets[0],
asset2: assets[1],
lastField: 'from',
},
resolver: (formValues) =>
validateForm(
formValues,
account,
setValue,
setLoading,
setRealData,
setShowSwapInfo,
),
});
function setRealData(
values: FormValues,
calculatedResult: ServerApi.PaymentPathRecord,
) {
clearErrors('from');
clearErrors('to');
setIsRotateActive(false);
const calculatePath = [
values.asset1,
...calculatedResult.path,
values.asset2,
];
setPath(calculatePath);
if (values.lastField === 'from') {
setValue('to', calculatedResult.destination_amount);
const minReceived = new BN(calculatedResult.destination_amount)
.div(100)
.times(config.MIN_RECEIVED);
setMinimumReceived(parseFloat(minReceived.toString()));
} else {
setValue('from', calculatedResult.source_amount);
if (
!isInsufficientAsset(
values.asset1,
account.subentry_count,
values.from,
)
) {
errors.from = {
type: 'error',
message: 'Insufficient amount.',
};
}
const minReceived = new BN(values.to)
.div(100)
.times(config.MIN_RECEIVED);
setMinimumReceived(parseFloat(minReceived.toString()));
}
setShowSwapInfo(true);
}
useEffect(() => {
trigger();
}, [useWatch({ name: ['asset1', 'asset2'], control })]);
const setFromMax = () => {
const formValues = getValues();
const maxValue = getMaxBalance(formValues.asset1, account);
setValue('from', maxValue, {
shouldValidate: true,
});
setValue('to', '0');
};
const handleSwapPlaces = () => {
const { to, from, asset1, asset2 } = getValues();
setValue('asset1', asset2, {
shouldValidate: true,
});
setValue('asset2', asset1, {
shouldValidate: true,
});
setValue('to', from);
setValue('from', to);
};
const onSubmit = (v: FormValues) => {
setShowSwapInfo(false);
const values = {
...v,
path,
minimumReceived,
};
if (usage === 'extension') {
navigate(RouteName.BasicSwapConfirm, {
state: {
values,
},
});
} else {
openModalAction({
title: '',
isStyled: false,
size: 'medium',
padding: 'medium',
minHeight: 0,
children: (
<div className="px-8 pt-8 pb-[14px] min-h-[534px]">
<BasicConfirmSwap usage="desktop" values={values} />
</div>
),
});
}
reset();
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label className="label-primary block mt-[12px]">From</label>
<S.ModalInput>
<Controller
name="lastField"
control={control}
render={({ field }) => (
<Input
invisible
type="text"
size="medium"
value={field.value}
onChange={field.onChange}
errorMsg={errors.lastField && errors.lastField.message}
/>
)}
/>
<Controller
name="from"
control={control}
render={({ field }) => (
<Input
type="number"
placeholder="0.0"
size="medium"
variant="max"
value={field.value}
onChange={(e) => {
setValue('lastField', 'from');
field.onChange(e);
}}
setMax={setFromMax}
errorMsg={errors.from && errors.from.message}
onKeyPress={controlNumberInput}
styleType="light"
className="grow"
/>
)}
/>
<Controller
name="asset1"
control={control}
render={({ field }) => (
<SelectAssetModal
usage={usage}
valueName="asset1"
asset={field.value}
onChange={field.onChange}
assets={assets}
/>
)}
/>
</S.ModalInput>
<div className="flex justify-center">
<div
style={{
width: 32,
height: 32,
borderRadius: '50%',
overflow: 'hidden',
cursor: 'pointer',
}}
onClick={handleSwapPlaces}
>
<Swap />
</div>
</div>
<label className="label-primary block mt-[-28px]">To</label>
<S.ModalInput>
<Controller
name="to"
control={control}
render={({ field }) => (
<Input
type="number"
placeholder="0.0"
size="medium"
value={field.value}
onChange={(e) => {
setValue('lastField', 'to');
field.onChange(e);
}}
errorMsg={errors.to && errors.to.message}
onKeyPress={controlNumberInput}
styleType="light"
className="grow"
/>
)}
/>
<Controller
name="asset2"
control={control}
render={({ field }) => (
<SelectAssetModal
usage={usage}
asset={field.value}
valueName="asset2"
assets={assets}
onChange={field.onChange}
/>
)}
/>
</S.ModalInput>
{loading ? (
<div className="flex justify-center">
<Loading size={40} className="!p-0" />
</div>
) : (
''
)}
{showSwapInfo ? (
<>
<div className="flex items-center justify-end">
<div className="mr-1">
<ShowFractional
control={control}
isRotateActive={isRotateActive}
/>
</div>
<S.Rotate isRotate={shouldRotate}>
<span
onClick={() => {
setIsRotateActive(!isRotateActive);
setShouldRotate(true);
setTimeout(() => {
setShouldRotate(false);
}, 500);
}}
>
<Rotate />
</span>
</S.Rotate>
</div>
<S.Hr />
<SwapDetail
path={path}
control={control}
minimumReceived={minimumReceived}
/>
</>
) : (
''
)}
<ButtonContainer
btnSize={usage === 'extension' ? 100 : 104}
justify="end"
positionStyles={{
bottom: '32px',
}}
mt={40}
>
{usage !== 'desktop' ? (
<Button
type="button"
variant="default"
size="medium"
content="Cancel"
onClick={() => {
navigate('/', {
state: {
alreadyLoaded: true,
},
});
}}
style={{ marginRight: '7px' }}
/>
) : (
''
)}
<Button
type="submit"
variant="primary"
size="medium"
content="Swap"
style={{ marginRight: '-12px' }}
disabled={!isValid || isValidating || !showSwapInfo}
/>
</ButtonContainer>
</form>
);
}
Example #27
Source File: edit-general.tsx From admin with MIT License | 4 votes |
EditGeneral: React.FC<EditGeneralProps> = ({ discount, onClose }) => {
const { mutate, isLoading } = useAdminUpdateDiscount(discount.id)
const notification = useNotification()
const { control, handleSubmit, reset, register } = useForm<GeneralForm>({
defaultValues: mapGeneral(discount),
})
const onSubmit = (data: GeneralForm) => {
mutate(
{
regions: data.regions.map((r) => r.value),
code: data.code,
rule: {
id: discount.rule.id,
description: data.description,
value: data.value,
allocation: discount.rule.allocation,
},
},
{
onSuccess: ({ discount }) => {
notification("Success", "Discount updated successfully", "success")
reset(mapGeneral(discount))
onClose()
},
onError: (error) => {
notification("Error", getErrorMessage(error), "error")
},
}
)
}
useEffect(() => {
reset(mapGeneral(discount))
}, [discount])
const type = discount.rule.type
const { regions } = useAdminRegions()
const regionOptions = useMemo(() => {
return regions
? regions.map((r) => ({
label: r.name,
value: r.id,
}))
: []
}, [regions])
const selectedRegions = useWatch<Option[]>({
control,
name: "regions",
})
const fixedCurrency = useMemo(() => {
if (type === "fixed" && selectedRegions?.length) {
return regions?.find((r) => r.id === selectedRegions[0].value)
?.currency_code
}
}, [selectedRegions, type, regions])
return (
<Modal handleClose={onClose}>
<form onSubmit={handleSubmit(onSubmit)}>
<Modal.Body>
<Modal.Header handleClose={onClose}>
<h1 className="inter-xlarge-semibold">Edit general information</h1>
</Modal.Header>
<Modal.Content isLargeModal>
<Controller
name="regions"
control={control}
rules={{
required: "Atleast one region is required",
validate: (value) =>
Array.isArray(value) ? value.length > 0 : !!value,
}}
render={({ value, onChange }) => {
return (
<Select
value={value}
onChange={(value) => {
onChange(type === "fixed" ? [value] : value)
}}
label="Choose valid regions"
isMultiSelect={type !== "fixed"}
hasSelectAll={type !== "fixed"}
enableSearch
required
options={regionOptions}
/>
)
}}
/>
<div className="flex gap-x-base gap-y-base my-base">
<InputField
label="Code"
className="flex-1"
placeholder="SUMMERSALE10"
required
name="code"
ref={register({ required: "Code is required" })}
/>
{type !== "free_shipping" && (
<>
{type === "fixed" ? (
<div className="flex-1">
<CurrencyInput
size="small"
currentCurrency={fixedCurrency ?? "USD"}
readOnly
hideCurrency
>
<Controller
name="value"
control={control}
rules={{
required: "Amount is required",
min: 1,
}}
render={({ value, onChange }) => {
return (
<CurrencyInput.AmountInput
label={"Amount"}
required
amount={value}
onChange={onChange}
/>
)
}}
/>
</CurrencyInput>
</div>
) : (
<div className="flex-1">
<InputField
label="Percentage"
min={0}
required
type="number"
placeholder="10"
prefix={"%"}
name="value"
ref={register({
required: "Percentage is required",
valueAsNumber: true,
})}
/>
</div>
)}
</>
)}
</div>
<div className="text-grey-50 inter-small-regular flex flex-col mb-6">
<span>
The code your customers will enter during checkout. This will
appear on your customer’s invoice.
</span>
<span>Uppercase letters and numbers only.</span>
</div>
<Textarea
label="Description"
required
placeholder="Summer Sale 2022"
rows={1}
name="description"
ref={register({
required: "Description is required",
})}
/>
</Modal.Content>
<Modal.Footer>
<div className="gap-x-xsmall flex items-center justify-end w-full">
<Button
variant="ghost"
size="small"
className="min-w-[128px]"
type="button"
onClick={onClose}
>
Cancel
</Button>
<Button
variant="primary"
size="small"
className="min-w-[128px]"
type="submit"
loading={isLoading}
>
Save
</Button>
</div>
</Modal.Footer>
</Modal.Body>
</form>
</Modal>
)
}
Example #28
Source File: PaymentMethodsInput.tsx From coindrop with GNU General Public License v3.0 | 4 votes |
PaymentMethodsInput: FC<Props> = ({ fieldArrayName, fields, control, register, remove, append }) => {
const { colors } = useTheme();
const paymentMethodsDataWatch: PaymentMethod[] = useWatch({
control,
name: fieldArrayName,
});
const [openAccordionItemIndex, setOpenAccordionItemIndex] = useState(-1);
useEffect(() => {
if (
paymentMethodsDataWatch[paymentMethodsDataWatch.length - 1]?.paymentMethodId === "default-blank"
|| paymentMethodsDataWatch[paymentMethodsDataWatch.length - 1]?.address === ""
) {
setOpenAccordionItemIndex(paymentMethodsDataWatch.length - 1);
}
}, [paymentMethodsDataWatch]);
const containsInvalidAddress = paymentMethodsDataWatch.some(paymentMethod => !paymentMethod.address);
const { isAddressTouched, setIsAddressTouched } = useContext(AdditionalValidation);
// optgroup not compatible with Chakra dark mode: https://github.com/chakra-ui/chakra-ui/issues/2853
// const optionsGroup = (category: Category) => {
// const optgroupLabels: Record<Category, string> = {
// "digital-wallet": 'Digital Wallets',
// "digital-asset": "Digital Assets",
// "subscription-platform": "Subscription Platforms",
// };
// return (
// <optgroup label={optgroupLabels[category]}>
// {paymentMethods
// .filter(paymentMethod => paymentMethod.category === category)
// .sort((a, b) => (a.id < b.id ? -1 : 1))
// .map(({ id, displayName }) => (
// <option
// key={id}
// value={id}
// style={{display: paymentMethodsDataWatch.map(paymentMethodDataWatch => paymentMethodDataWatch.paymentMethodId).includes(id) ? "none" : undefined }}
// >
// {displayName}
// </option>
// ))}
// </optgroup>
// );
// };
return (
<>
{fields.length < 1
? 'No payment methods defined yet.'
: (
<Accordion
allowToggle
defaultIndex={-1}
index={openAccordionItemIndex}
>
{
fields
.map((item, index) => {
const watchedData = paymentMethodsDataWatch.find(watchedPaymentMethod => watchedPaymentMethod.id === item.id);
const PaymentMethodIcon = paymentMethodIcons[watchedData?.paymentMethodId];
return (
<AccordionItem
key={item.id}
>
<AccordionButton
onClick={() => {
setIsAddressTouched(true);
if (openAccordionItemIndex !== index && !paymentMethodsDataWatch.find(paymentMethod => paymentMethod.address === "")) {
setOpenAccordionItemIndex(index);
} else {
setOpenAccordionItemIndex(undefined);
}
}}
>
<Flex flex="1" textAlign="left" align="center">
<Flex mr={1} align="center">
{PaymentMethodIcon ? <PaymentMethodIcon mr={2} /> : <QuestionOutlineIcon mr={2} />}
{paymentMethodNames[watchedData?.paymentMethodId] ?? 'Add payment method'}
</Flex>
{watchedData?.isPreferred && (
<Flex>
<StarIcon
ml={2}
size="16px"
color={colors.yellow['400']}
/>
<Text
as="span"
fontSize="xs"
ml={1}
>
<i>Preferred</i>
</Text>
</Flex>
)}
</Flex>
<AccordionIcon />
</AccordionButton>
<AccordionPanel pb={4} id={`accordion-panel-${watchedData.paymentMethodId}`}>
<input
ref={register()}
name={`${fieldArrayName}[${index}].id`}
defaultValue={item.id}
style={{display: 'none'}}
/>
<Box
display={paymentMethodNames[watchedData?.paymentMethodId] ? "none" : "block"}
data-cy={`select-payment-method-container-${watchedData.paymentMethodId}`}
>
<Select
name={`${fieldArrayName}[${index}].paymentMethodId`}
ref={register()}
defaultValue={paymentMethodNames[item.paymentMethodId] ? item.paymentMethodId : 'default-blank'}
isInvalid={containsInvalidAddress && isAddressTouched}
onChange={() => setIsAddressTouched(false)}
>
<option hidden disabled value="default-blank">Select...</option>
{/* optgroup not compatible with Chakra dark mode: https://github.com/chakra-ui/chakra-ui/issues/2853 */}
{Object.entries(paymentMethodNames)
.sort((a, b) => {
const [aId] = a;
const [bId] = b;
return aId < bId ? -1 : 1;
})
.map(([paymentMethodId, paymentMethodDisplayName]) => (
<option
key={paymentMethodId}
value={paymentMethodId}
style={{display: paymentMethodsDataWatch.map(paymentMethod => paymentMethod.paymentMethodId).includes(paymentMethodId) ? "none" : undefined }}
>
{paymentMethodDisplayName}
</option>
))}
</Select>
</Box>
<Box
mx={3}
display={paymentMethodNames[watchedData?.paymentMethodId] ? "block" : "none"}
>
<FormControl isRequired>
<FormLabel htmlFor={`${fieldArrayName}[${index}].address`}>Address</FormLabel>
<Input
id={`address-input-${watchedData.paymentMethodId}`}
name={`${fieldArrayName}[${index}].address`}
ref={register()}
defaultValue={item.address}
isInvalid={containsInvalidAddress && isAddressTouched}
/>
<Box>
<Checkbox
name={`${fieldArrayName}[${index}].isPreferred`}
ref={register()}
defaultValue={item?.isPreferred ? 1 : 0}
defaultIsChecked={item?.isPreferred}
mt={1}
colorScheme="yellow"
>
Preferred
</Checkbox>
</Box>
</FormControl>
</Box>
<Flex
justify={watchedData?.paymentMethodId === 'default-blank' ? 'space-between' : 'flex-end'}
mt={3}
wrap="wrap"
align="center"
>
{watchedData?.paymentMethodId === 'default-blank' && (
<Text fontSize="xs" ml={1}>
<Link href="/blog/payment-method-request" isExternal>
Payment method not listed?
</Link>
</Text>
)}
<Button
onClick={() => {
remove(index);
setIsAddressTouched(false);
}}
leftIcon={<MinusIcon />}
size="sm"
>
{'Remove '}
{/* {paymentMethodNames[watchedData?.paymentMethodId]} */}
</Button>
</Flex>
</AccordionPanel>
</AccordionItem>
);
})
}
</Accordion>
)}
<Flex
justify="center"
mt={2}
>
<Button
id="add-payment-method-button"
onClick={() => {
append({});
setIsAddressTouched(false);
}}
leftIcon={<AddIcon />}
variant="ghost"
size="sm"
isDisabled={
(
fields.length > 0
&& !paymentMethodNames[paymentMethodsDataWatch[paymentMethodsDataWatch.length - 1]?.paymentMethodId]
)
|| containsInvalidAddress
}
>
Add payment method
</Button>
</Flex>
</>
);
}
Example #29
Source File: RealEstate.tsx From UsTaxes with GNU Affero General Public License v3.0 | 4 votes |
export default function RealEstate(): ReactElement {
const defaultValues = blankAddForm
const methods = useForm<PropertyAddForm>({ defaultValues })
const { handleSubmit, control, getValues } = methods
const dispatch = useDispatch()
const { onAdvance, navButtons } = usePager()
const activeYear: TaxYear = useSelector(
(state: YearsTaxesState) => state.activeYear
)
const properties: Property[] = useYearSelector(
(state) => state.information.realEstate
)
const propertyType = useWatch({
control,
name: 'propertyType'
})
const otherExpensesEntered: number | undefined = useWatch({
control,
name: 'expenses.other'
})
const validateDays = (n: number, other: number): Message | true => {
const days = daysInYear(TaxYears[activeYear])
return n + other <= days ? true : `Total use days must be less than ${days}`
}
const validatePersonal = (n: number): Message | true =>
validateDays(n, Number(getValues().rentalDays ?? 0))
const validateRental = (n: number): Message | true =>
validateDays(n, Number(getValues().personalUseDays ?? 0))
const deleteProperty = (n: number): void => {
dispatch(removeProperty(n))
}
const onAddProperty = (formData: PropertyAddForm): void => {
dispatch(addProperty(toProperty(formData)))
}
const onEditProperty =
(index: number) =>
(formData: PropertyAddForm): void => {
dispatch(editProperty({ value: toProperty(formData), index }))
}
const expenseFields: ReactElement[] = enumKeys(PropertyExpenseType).map(
(k, i) => (
<LabeledInput
key={i}
label={displayExpense(PropertyExpenseType[k])}
name={`expenses.${k.toString()}`}
patternConfig={Patterns.currency}
required={false}
/>
)
)
const otherExpenseDescription = (() => {
if ((otherExpensesEntered ?? 0) !== 0) {
return (
<LabeledInput
key={enumKeys(PropertyExpenseType).length}
label="Other description"
name="otherExpenseType"
required={true}
/>
)
}
})()
const form = (
<FormListContainer
defaultValues={defaultValues}
items={properties.map((a) => toUserInput(a))}
icon={() => <HouseOutlined />}
primary={(p) => toProperty(p).address.address}
secondary={(p) => <Currency value={toProperty(p).rentReceived} />}
onSubmitAdd={onAddProperty}
onSubmitEdit={onEditProperty}
removeItem={(i) => deleteProperty(i)}
>
<h3>Property Location</h3>
<Grid container spacing={2}>
<AddressFields
autofocus={true}
checkboxText="Does the property have a foreign address"
allowForeignCountry={false}
/>
<GenericLabeledDropdown
dropDownData={enumKeys(PropertyType)}
label="Property type"
textMapping={(t) => displayPropertyType(PropertyType[t])}
keyMapping={(_, n) => n}
name="propertyType"
valueMapping={(n) => n}
/>
{(() => {
if (propertyType === 'other') {
return (
<LabeledInput
name="otherPropertyType"
label="Short property type description"
required={true}
/>
)
}
})()}
</Grid>
<h3>Use</h3>
<Grid container spacing={2}>
<LabeledInput
name="rentalDays"
rules={{ validate: (n: string) => validateRental(Number(n)) }}
label="Number of days in the year used for rental"
patternConfig={Patterns.numDays(activeYear)}
/>
<LabeledInput
name="personalUseDays"
rules={{ validate: (n: string) => validatePersonal(Number(n)) }}
label="Number of days in the year for personal use"
patternConfig={Patterns.numDays(activeYear)}
/>
<LabeledCheckbox
name="qualifiedJointVenture"
label="Is this a qualified joint venture"
/>
</Grid>
<h3>Property Financials</h3>
<h4>Income</h4>
<Grid container spacing={2}>
<LabeledInput
name="rentReceived"
label="Rent received"
patternConfig={Patterns.currency}
/>
</Grid>
<h4>Expenses</h4>
<Grid container spacing={2}>
{_.chain([...expenseFields, otherExpenseDescription])
.chunk(2)
.map((segment, i) =>
segment.map((item, k) => (
<Grid item key={`${i}-${k}`} xs={12} sm={6}>
{item}
</Grid>
))
)
.value()}
</Grid>
</FormListContainer>
)
return (
<FormProvider {...methods}>
<form
tabIndex={-1}
onSubmit={intentionallyFloat(handleSubmit(onAdvance))}
>
<Helmet>
<title>Real Estate | Income | UsTaxes.org</title>
</Helmet>
<h2>Properties</h2>
{form}
{navButtons}
</form>
</FormProvider>
)
}