Skip to content

Commit

Permalink
add station API calls to trade/single form (#141)
Browse files Browse the repository at this point in the history
* implement GET calls for station names

* new react select form component
  • Loading branch information
aslink87 authored May 21, 2024
1 parent 56ca363 commit 2c03729
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 71 deletions.
26 changes: 1 addition & 25 deletions app/_components/inputs/Systems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,6 @@ type FieldOptions = {
isMulti?: true;
};

/* Swap out for live lookup when data is available? */
const getMockSystemName = async (lookupString: string) => {
const res = await fetch(
`${process.env.NEXT_PUBLIC_MOCK_API_URL}/api/v1/exploration/system/by-name-containing`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: lookupString }),
},
);

if (!res.ok) {
throw new Error(`HTTP error! status: ${res.status}`);
}

return res.json();
};

const getSystemName = async (lookupString: string) => {
const res = await fetch(
`${process.env.NEXT_PUBLIC_STAGING_API_URL}/api/v1/exploration/system/by-name-containing?subString=${lookupString}&amount=10`,
Expand All @@ -69,11 +49,7 @@ const loadOptions = async (inputValue: string): Promise<SelectGroup[] | []> => {
try {
let res = [];

if (process.env.NODE_ENV === 'development') {
res = await getMockSystemName(inputValue);
} else {
res = await getSystemName(inputValue);
}
res = await getSystemName(inputValue);

const returnArr: SelectGroup[] = res.map((item: ISystem) => ({
value: item.eliteId,
Expand Down
55 changes: 55 additions & 0 deletions app/_components/inputs/form/ChakraReactSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useEffect, useState } from 'react';
import { Controller } from 'react-hook-form';
import { Select as ChakraSelect } from 'chakra-react-select';
import SelectStyles from '@/app/_hooks/SelectStyles';

interface Props {
fieldName: string;
options: string[];
control: any;
placeholder: string;
}

// consumes an array of strings {options} and outputs a styled selection component with search functionality
const ChakraReactSelect = ({
fieldName,
options,
control,
placeholder,
}: Props) => {
const [optionsState, setOptionsState] = useState<
{ label: string; value: string }[]
>([]);

const formatOptions = () =>
options.map((val) => ({
label: val,
value: val,
}));

useEffect(() => {
setOptionsState(formatOptions());
}, [options]);

return (
<Controller
control={control}
name={fieldName}
render={({ field: { onChange, onBlur, value, name, ref } }) => (
<ChakraSelect
isClearable
name={name}
ref={ref}
onChange={onChange}
onBlur={onBlur}
options={optionsState}
placeholder={placeholder}
value={value}
chakraStyles={SelectStyles()}
/>
)}
/>
);
};

export default ChakraReactSelect;
113 changes: 68 additions & 45 deletions app/_components/trade-routes/single/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm, SubmitHandler } from 'react-hook-form';
Expand All @@ -23,18 +23,28 @@ import {
} from '@chakra-ui/react';
import { ICommodity } from '@/app/_types';
import ExpandIcon from '../../utility/ExpandIcon';
import { useGetData } from '@/app/_lib/api-calls';
import ChakraReactSelect from '../../inputs/form/ChakraReactSelect';

export const SingleTradeRouteFormSchema = z.object({
buySystemName: z
.object({ label: z.string() })
.object({ label: z.string(), value: z.number() })
.optional()
.transform((val) => val?.label),
buyStationName: z.string().optional(),
.nullable(),
buyStationName: z
.object({ label: z.string(), value: z.string() })
.optional()
.nullable()
.transform((val) => val?.value),
sellSystemName: z
.object({ label: z.string() })
.object({ label: z.string(), value: z.number() })
.optional()
.nullable(),
sellStationName: z
.object({ label: z.string(), value: z.string() })
.optional()
.transform((val) => val?.label),
sellStationName: z.string().optional(),
.nullable()
.transform((val) => val?.value),
commodityDisplayName: z
.array(z.object({ value: z.string() }))
.optional()
Expand Down Expand Up @@ -76,26 +86,63 @@ const Form: React.FC<FormProps> = ({
commodities,
}) => {
const [isExpanded, setIsExpanded] = useState(false);

const [buySystemStations, setBuySystemStations] = useState<string[]>([]);
const [sellSystemStations, setSellSystemStations] = useState<string[]>([]);

const {
control,
register,
handleSubmit,
watch,
formState: { errors },
} = useForm<SubmitProps>({
defaultValues: {
maxPriceAgeHours: 72,
},
resolver: zodResolver(SingleTradeRouteFormSchema),
});
const buySystem = watch('buySystemName', { value: 0, label: '' });
const sellSystem = watch('sellSystemName', { value: 0, label: '' });

const { data: buyStationData, mutate: buyStationMutate } = useGetData(
`exploration/system/list-station-names?systemName=${buySystem?.label}`,
);

const { data: sellStationData, mutate: sellStationMutate } = useGetData(
`exploration/system/list-station-names?systemName=${sellSystem?.label}`,
);

useEffect(() => {
const systemName = buySystem?.label;
const fetchData = async () => {
await buyStationMutate();
};

if (systemName) fetchData();
}, [buySystem, buyStationMutate]);

useEffect(() => {
if (buyStationData) setBuySystemStations(buyStationData);
}, [buyStationData]);

useEffect(() => {
const systemName = sellSystem?.label;
const fetchData = async () => {
await sellStationMutate();
};

if (systemName) fetchData();
}, [sellSystem, sellStationMutate]);

useEffect(() => {
if (sellStationData) setSellSystemStations(sellStationData);
}, [sellStationData]);

const onSubmit: SubmitHandler<SubmitProps> = (data) => {
onSubmitHandler(data);
};

// For demo purposes
const [buySystemStations, setBuySystemStations] = useState<string[]>([]);
const [sellSystemStations, setSellSystemStations] = useState<string[]>([]);

return (
<form onSubmit={handleSubmit(onSubmit)}>
<Grid
Expand All @@ -116,11 +163,6 @@ const Form: React.FC<FormProps> = ({
fieldName="buySystemName"
control={control}
placeholder="Select a system..."
onChange={(newValue) => {
setBuySystemStations(
newValue ? ['Station1', 'Station2', 'Station3'] : [],
);
}}
/>
<FormErrorMessage>
{errors.buySystemName && errors.buySystemName.message}
Expand All @@ -135,23 +177,16 @@ const Form: React.FC<FormProps> = ({
}
>
<FormLabel>Buy from Station</FormLabel>
<Select
register={register('buyStationName', {
disabled: buySystemStations.length === 0,
})}
<ChakraReactSelect
fieldName="buyStationName"
options={buySystemStations}
control={control}
placeholder={
buySystemStations.length === 0
? 'Enter a system first...'
: 'Select a station (optional)'
}
>
{buySystemStations.length &&
buySystemStations.map((station) => (
<option key={station} value={station}>
{station}
</option>
))}
</Select>
/>
<FormErrorMessage>
{errors.buyStationName && errors.buyStationName.message}
</FormErrorMessage>
Expand All @@ -169,11 +204,6 @@ const Form: React.FC<FormProps> = ({
fieldName="sellSystemName"
control={control}
placeholder="Select a system..."
onChange={(newValue) => {
setSellSystemStations(
newValue ? ['Station1', 'Station2', 'Station3'] : [],
);
}}
/>
<FormErrorMessage>
{errors.sellSystemName && errors.sellSystemName.message}
Expand All @@ -188,23 +218,16 @@ const Form: React.FC<FormProps> = ({
}
>
<FormLabel>Sell to Station</FormLabel>
<Select
register={register('sellStationName', {
disabled: sellSystemStations.length === 0,
})}
<ChakraReactSelect
fieldName="sellStationName"
options={sellSystemStations}
control={control}
placeholder={
sellSystemStations.length === 0
? 'Enter a system first...'
: 'Select a station (optional)'
}
>
{sellSystemStations.length &&
sellSystemStations.map((station) => (
<option key={station} value={station}>
{station}
</option>
))}
</Select>
/>
<FormErrorMessage>
{errors.sellStationName && errors.sellStationName.message}
</FormErrorMessage>
Expand Down
21 changes: 21 additions & 0 deletions app/_lib/api-calls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,29 @@ const useGetMockSubmitFormClient = (queryString: string) => {
};
};

// typical request fetching data from staging URL
const useGetData = (queryString: string) => {
const { data, error, isLoading, mutate } = useSWR(
`${process.env.NEXT_PUBLIC_STAGING_API_URL}/api/v1/${queryString}`,
fetcher,
{
shouldRetryOnError: false,
revalidateOnFocus: false,
revalidateOnMount: false,
},
);

return {
data,
isLoading,
error,
mutate,
};
};

export {
getFormElementDataServer,
useGetSubmitFormClient,
useGetMockSubmitFormClient,
useGetData,
};
2 changes: 1 addition & 1 deletion app/trade/single/page.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const PageClient = ({ commodities }: IPageClientProps) => {
...data,
};

// TODO: submit data to backend
// TODO: format and submit data to backend
setTimeout(() => {
console.log('submitted ', submitData);
setIsLoading(false);
Expand Down

0 comments on commit 2c03729

Please sign in to comment.