From e8881b5b66d03b31b3decc6d6a5c7e0fd782390f Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Tue, 14 May 2024 20:36:11 -0300 Subject: [PATCH 01/15] feat: useGeolocation hook --- src/hooks/index.ts | 2 + src/hooks/useGeolocation/index.ts | 3 ++ src/hooks/useGeolocation/types.ts | 5 ++ src/hooks/useGeolocation/useGeolocation.tsx | 57 +++++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 src/hooks/useGeolocation/index.ts create mode 100644 src/hooks/useGeolocation/types.ts create mode 100644 src/hooks/useGeolocation/useGeolocation.tsx diff --git a/src/hooks/index.ts b/src/hooks/index.ts index b953455d..676bcc1b 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -5,6 +5,7 @@ import { useThrottle } from './useThrottle'; import { useShelter } from './useShelter'; import { useSupplyCategories } from './useSupplyCategories'; import { useSupplies } from './useSupplies'; +import { useGeolocation } from './useGeolocation'; export { useShelters, @@ -14,4 +15,5 @@ export { useShelter, useSupplyCategories, useSupplies, + useGeolocation, }; diff --git a/src/hooks/useGeolocation/index.ts b/src/hooks/useGeolocation/index.ts new file mode 100644 index 00000000..73a1fa50 --- /dev/null +++ b/src/hooks/useGeolocation/index.ts @@ -0,0 +1,3 @@ +import { useGeolocation } from './useGeolocation'; + +export { useGeolocation }; diff --git a/src/hooks/useGeolocation/types.ts b/src/hooks/useGeolocation/types.ts new file mode 100644 index 00000000..876fdf19 --- /dev/null +++ b/src/hooks/useGeolocation/types.ts @@ -0,0 +1,5 @@ +export interface IGeolocation { + latitude: number; + longitude: number; + radiusInMeters?: number; +} diff --git a/src/hooks/useGeolocation/useGeolocation.tsx b/src/hooks/useGeolocation/useGeolocation.tsx new file mode 100644 index 00000000..5b799e14 --- /dev/null +++ b/src/hooks/useGeolocation/useGeolocation.tsx @@ -0,0 +1,57 @@ +import { useState, useCallback } from 'react'; + +import { IGeolocation } from './types'; + +export const useGeolocation = (isForceReresh = false) => { + const [geolocation, setGeolocation] = useState({ + latitude: 0, + longitude: 0, + }); + const [error, setError] = useState(''); + const [isLoading, setIsLoading] = useState(false); + + const showPosition = (position: GeolocationPosition) => { + const { latitude, longitude } = position.coords; + setGeolocation({ latitude, longitude }); + setIsLoading(false); + setError(''); + }; + + const showError = (error: GeolocationPositionError) => { + switch (error.code) { + case error.PERMISSION_DENIED: + setError('É preciso liberar a permissão de geolocalização.'); + break; + case error.POSITION_UNAVAILABLE: + setError( + 'Infelizmente não foi possível obter sua posição, talvez seu dispositivo esteja desatualizado.' + ); + break; + case error.TIMEOUT: + setError('A requisição expirou, por favor tente novamente.'); + break; + + default: + setError( + 'Infelizmente não foi possível obter seu endereço neste dispositivo.' + ); + break; + } + setIsLoading(false); + }; + const getLocation = useCallback(() => { + if (isForceReresh || (geolocation.latitude && geolocation.longitude)) + return; + + setIsLoading(true); + if (!window.navigator.geolocation) return; + + window.navigator.geolocation.getCurrentPosition( + (position) => showPosition(position), + (error) => showError(error), + { enableHighAccuracy: true } + ); + }, [geolocation.latitude, geolocation.longitude, isForceReresh]); + + return { isLoading, getLocation, geolocation, error }; +}; From a2852567b2a6b6e6caa5478809278773e27e94f5 Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Tue, 14 May 2024 21:15:08 -0300 Subject: [PATCH 02/15] feat: proximity radius filter --- package-lock.json | 34 ++++ package.json | 7 +- src/components/ui/slider.tsx | 26 +++ src/pages/Home/components/Filter/Filter.tsx | 34 +++- .../Filter/LocationFilter/LocationFilter.tsx | 156 ++++++++++++++++++ .../components/Filter/LocationFilter/index.ts | 3 + .../components/Filter/LocationFilter/types.ts | 8 + src/pages/Home/components/Filter/types.ts | 3 + 8 files changed, 262 insertions(+), 9 deletions(-) create mode 100644 src/components/ui/slider.tsx create mode 100644 src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx create mode 100644 src/pages/Home/components/Filter/LocationFilter/index.ts create mode 100644 src/pages/Home/components/Filter/LocationFilter/types.ts diff --git a/package-lock.json b/package-lock.json index 33731021..e17a050a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@radix-ui/react-radio-group": "^1.1.3", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", + "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-tooltip": "^1.0.7", @@ -1828,6 +1829,39 @@ } } }, + "node_modules/@radix-ui/react-slider": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.1.2.tgz", + "integrity": "sha512-NKs15MJylfzVsCagVSWKhGGLNR1W9qWs+HtgbmjjVUB3B9+lb3PYoXxVju3kOrpf0VKyVCtZp+iTwVoqpa1Chw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/number": "1.0.1", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-controllable-state": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1", + "@radix-ui/react-use-previous": "1.0.1", + "@radix-ui/react-use-size": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", diff --git a/package.json b/package.json index 29dd3ef1..e4922119 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@radix-ui/react-radio-group": "^1.1.3", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", + "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-tooltip": "^1.0.7", @@ -28,12 +29,12 @@ "formik": "^2.4.6", "lucide-react": "^0.378.0", "qs": "^6.12.1", + "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.51.4", "react-input-mask": "^2.0.4", "react-router-dom": "^6.23.0", "react-select": "^5.8.0", - "react": "^18.2.0", "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", "yup": "^1.4.0" @@ -41,16 +42,16 @@ "devDependencies": { "@types/node": "^20.12.8", "@types/qs": "^6.9.15", + "@types/react": "^18.2.66", "@types/react-dom": "^18.2.22", "@types/react-input-mask": "^3.0.5", - "@types/react": "^18.2.66", "@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/parser": "^7.2.0", "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.19", + "eslint": "^8.57.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.6", - "eslint": "^8.57.0", "postcss": "^8.4.38", "tailwindcss": "^3.4.3", "typescript": "^5.2.2", diff --git a/src/components/ui/slider.tsx b/src/components/ui/slider.tsx new file mode 100644 index 00000000..d7f098ff --- /dev/null +++ b/src/components/ui/slider.tsx @@ -0,0 +1,26 @@ +import * as React from 'react'; +import * as SliderPrimitive from '@radix-ui/react-slider'; + +import { cn } from '@/lib/utils'; + +const Slider = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + + +)); +Slider.displayName = SliderPrimitive.Root.displayName; + +export { Slider }; diff --git a/src/pages/Home/components/Filter/Filter.tsx b/src/pages/Home/components/Filter/Filter.tsx index 98758218..691ddc64 100644 --- a/src/pages/Home/components/Filter/Filter.tsx +++ b/src/pages/Home/components/Filter/Filter.tsx @@ -22,6 +22,7 @@ import { } from './types'; import { priorityOptions } from '@/lib/utils'; import { ISupply, SupplyPriority } from '@/service/supply/types'; +import LocationFilter from './LocationFilter/LocationFilter'; const ShelterAvailabilityStatusMapped: Record< ShelterAvailabilityStatus, @@ -57,8 +58,8 @@ const Filter = (props: IFilterProps) => { {} as Record ); }, [supplies]); - const { handleSubmit, values, setFieldValue } = useFormik( - { + const { handleSubmit, values, setFieldValue, errors } = + useFormik({ initialValues: { priority: { value: data.priority ?? SupplyPriority.Urgent, @@ -77,6 +78,7 @@ const Filter = (props: IFilterProps) => { value: id, label: mappedSupplies[id]?.name, })), + geolocation: data.geolocation, }, enableReinitialize: true, validateOnChange: false, @@ -84,20 +86,33 @@ const Filter = (props: IFilterProps) => { validateOnMount: false, validationSchema: Yup.object().shape({ search: Yup.string(), + geolocation: Yup.object() + .shape({ + radiusInMeters: Yup.number().positive( + 'Raio em metros deve ser um número positivo' + ), + }) + .nullable(), }), onSubmit: (values) => { - const { priority, search, shelterStatus, supplies, supplyCategories } = - values; + const { + priority, + search, + shelterStatus, + supplies, + supplyCategories, + geolocation, + } = values; onSubmit({ priority: priority?.value ? +priority.value : null, search, shelterStatus: shelterStatus.map((s) => s.value), supplyCategoryIds: supplyCategories.map((s) => s.value), supplyIds: supplies.map((s) => s.value), + geolocation, }); }, - } - ); + }); const handleToggleShelterStatus = useCallback( (checked: boolean, status: ShelterAvailabilityStatus) => { @@ -135,6 +150,13 @@ const Filter = (props: IFilterProps) => { /> + +

Busca avançada diff --git a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx new file mode 100644 index 00000000..918fc9b1 --- /dev/null +++ b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx @@ -0,0 +1,156 @@ +import { useState, useEffect } from 'react'; +import { Loader } from 'lucide-react'; + +import { Button } from '@/components/ui/button'; +import { Slider } from '@/components/ui/slider'; +import { useGeolocation } from '@/hooks'; +import { ILocationFilter } from './types'; + +const MAX_PROXIMITY_IN_METERS = 200_000; +const PROXIMITY_INTERVAL_IN_METERS = 500; + +const LocationFilter = ({ + geolocationFormValues, + geolocationValues, + setFieldValue, + error, +}: ILocationFilter) => { + const { + isLoading, + geolocation, + getLocation, + error: errorGeolocation, + } = useGeolocation(); + const [isProximityChecked, setIsProximityChecked] = useState( + (Boolean(geolocationValues?.latitude) && + Boolean(geolocationValues?.longitude)) || + (Boolean(geolocationFormValues?.latitude) && + Boolean(geolocationFormValues?.longitude)) + ); + const normalizedRadiusMeters = + geolocationFormValues?.radiusInMeters ?? + geolocationValues?.radiusInMeters ?? + 0; + + useEffect(() => { + if (!isProximityChecked) return; + if (!geolocation.latitude) return; + if (!geolocation.latitude) return; + + setFieldValue( + 'geolocation.radiusInMeters', + geolocationValues?.radiusInMeters ?? 0 + ); + setFieldValue('geolocation.latitude', geolocation.latitude); + setFieldValue('geolocation.longitude', geolocation.longitude); + }, [ + geolocation.latitude, + geolocation.longitude, + geolocationValues?.radiusInMeters, + isProximityChecked, + setFieldValue, + ]); + + const showFilter = isProximityChecked && !errorGeolocation && !isLoading; + + return ( +

+
+
+ + + {Boolean(isLoading) && ( + + )} +
+ {Boolean(errorGeolocation) && ( + <> + {errorGeolocation && ( +

{errorGeolocation}

+ )} + + )} + {showFilter && ( + <> +
+

+ Selecione o raio máximo de abrigos na região(KM's ao redor) +

+ {Boolean(error) && ( +
+ {error &&

{error}

} +
+ )} + { + setFieldValue('geolocation.radiusInMeters', value[0]); + }} + name="geolocation.radiusInMeters" + className="" + /> +
+
+ + + {normalizedRadiusMeters / 1000} km + + +
+ + )} +
+
+ ); +}; + +export default LocationFilter; diff --git a/src/pages/Home/components/Filter/LocationFilter/index.ts b/src/pages/Home/components/Filter/LocationFilter/index.ts new file mode 100644 index 00000000..252b4317 --- /dev/null +++ b/src/pages/Home/components/Filter/LocationFilter/index.ts @@ -0,0 +1,3 @@ +import LocationFilter from './LocationFilter'; + +export { LocationFilter }; diff --git a/src/pages/Home/components/Filter/LocationFilter/types.ts b/src/pages/Home/components/Filter/LocationFilter/types.ts new file mode 100644 index 00000000..0e2f5c13 --- /dev/null +++ b/src/pages/Home/components/Filter/LocationFilter/types.ts @@ -0,0 +1,8 @@ +import { IGeolocation } from '@/hooks/useGeolocation/types'; + +export interface ILocationFilter { + geolocationFormValues?: IGeolocation; + geolocationValues?: IGeolocation; + setFieldValue: any; + error?: string; +} diff --git a/src/pages/Home/components/Filter/types.ts b/src/pages/Home/components/Filter/types.ts index 07c8bc08..638ddb82 100644 --- a/src/pages/Home/components/Filter/types.ts +++ b/src/pages/Home/components/Filter/types.ts @@ -1,3 +1,4 @@ +import { IGeolocation } from '@/hooks/useGeolocation/types'; import { SupplyPriority } from '@/service/supply/types'; export type ShelterAvailabilityStatus = 'available' | 'unavailable' | 'waiting'; @@ -13,6 +14,7 @@ export interface IFilterFormProps { supplyCategoryIds: string[]; supplyIds: string[]; shelterStatus: ShelterAvailabilityStatus[]; + geolocation?: IGeolocation; } export interface IFilterFormikProps { @@ -21,6 +23,7 @@ export interface IFilterFormikProps { supplyCategories: ISelectField[]; supplies: ISelectField[]; shelterStatus: ISelectField[]; + geolocation?: IGeolocation; } export interface IFilterProps { From b82bcce26ad31b9294116ccd0c4774c35cd21572 Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Tue, 14 May 2024 22:06:12 -0300 Subject: [PATCH 03/15] fix: max proximity --- .../Home/components/Filter/LocationFilter/LocationFilter.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx index 918fc9b1..192f6730 100644 --- a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx +++ b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx @@ -6,7 +6,7 @@ import { Slider } from '@/components/ui/slider'; import { useGeolocation } from '@/hooks'; import { ILocationFilter } from './types'; -const MAX_PROXIMITY_IN_METERS = 200_000; +const MAX_PROXIMITY_IN_METERS = 50_000; const PROXIMITY_INTERVAL_IN_METERS = 500; const LocationFilter = ({ From ac193af80dd5d76b25961bfacec4370510562445 Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Wed, 15 May 2024 01:43:42 -0300 Subject: [PATCH 04/15] fix: changed label and iterators position --- .../Filter/LocationFilter/LocationFilter.tsx | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx index 192f6730..aac691b1 100644 --- a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx +++ b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx @@ -100,6 +100,37 @@ const LocationFilter = ({ {error &&

{error}

}
)} +
+ + + {normalizedRadiusMeters / 1000} km + + +
-
- - - {normalizedRadiusMeters / 1000} km - - -
)} From 7eec5613a2ff9e4a5e0505e9257df803fd224ddd Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Wed, 15 May 2024 13:10:36 -0300 Subject: [PATCH 05/15] fix: z-index of header to same as modal --- src/components/Header/Header.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 1230b72e..6dc28a25 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -16,7 +16,7 @@ const Header = React.forwardRef((props, ref) => {
Date: Wed, 15 May 2024 13:11:17 -0300 Subject: [PATCH 06/15] feat: link when geolocation presents error --- src/hooks/useGeolocation/types.ts | 9 +++++ src/hooks/useGeolocation/useGeolocation.tsx | 28 +++++++-------- src/pages/Home/components/Filter/Filter.tsx | 2 +- .../Filter/LocationFilter/LocationFilter.tsx | 35 +++++++++++++++++-- .../components/Filter/LocationFilter/utils.ts | 10 ++++++ 5 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 src/pages/Home/components/Filter/LocationFilter/utils.ts diff --git a/src/hooks/useGeolocation/types.ts b/src/hooks/useGeolocation/types.ts index 876fdf19..250622a9 100644 --- a/src/hooks/useGeolocation/types.ts +++ b/src/hooks/useGeolocation/types.ts @@ -3,3 +3,12 @@ export interface IGeolocation { longitude: number; radiusInMeters?: number; } + +export const GeolocationError = { + PERMISSION_DENIED: 'É preciso liberar a permissão de geolocalização.', + POSITION_UNAVAILABLE: + 'Infelizmente não foi possível obter sua posição, talvez seu dispositivo esteja desatualizado.', + TIMEOUT: 'A requisição expirou, por favor tente novamente.', + DEFAULT: + 'Infelizmente não foi possível obter seu endereço neste dispositivo.', +}; diff --git a/src/hooks/useGeolocation/useGeolocation.tsx b/src/hooks/useGeolocation/useGeolocation.tsx index 5b799e14..1c6dab12 100644 --- a/src/hooks/useGeolocation/useGeolocation.tsx +++ b/src/hooks/useGeolocation/useGeolocation.tsx @@ -1,8 +1,8 @@ import { useState, useCallback } from 'react'; -import { IGeolocation } from './types'; +import { GeolocationError, IGeolocation } from './types'; -export const useGeolocation = (isForceReresh = false) => { +export const useGeolocation = () => { const [geolocation, setGeolocation] = useState({ latitude: 0, longitude: 0, @@ -20,28 +20,28 @@ export const useGeolocation = (isForceReresh = false) => { const showError = (error: GeolocationPositionError) => { switch (error.code) { case error.PERMISSION_DENIED: - setError('É preciso liberar a permissão de geolocalização.'); + setError(GeolocationError.PERMISSION_DENIED); break; case error.POSITION_UNAVAILABLE: - setError( - 'Infelizmente não foi possível obter sua posição, talvez seu dispositivo esteja desatualizado.' - ); + setError(GeolocationError.PERMISSION_DENIED); break; case error.TIMEOUT: - setError('A requisição expirou, por favor tente novamente.'); + setError(GeolocationError.TIMEOUT); break; default: - setError( - 'Infelizmente não foi possível obter seu endereço neste dispositivo.' - ); + setError(GeolocationError.DEFAULT); break; } setIsLoading(false); }; + + const clearData = () => { + setGeolocation({ latitude: 0, longitude: 0 }); + }; + const getLocation = useCallback(() => { - if (isForceReresh || (geolocation.latitude && geolocation.longitude)) - return; + if (geolocation.latitude && geolocation.longitude) return; setIsLoading(true); if (!window.navigator.geolocation) return; @@ -51,7 +51,7 @@ export const useGeolocation = (isForceReresh = false) => { (error) => showError(error), { enableHighAccuracy: true } ); - }, [geolocation.latitude, geolocation.longitude, isForceReresh]); + }, [geolocation.latitude, geolocation.longitude]); - return { isLoading, getLocation, geolocation, error }; + return { isLoading, getLocation, clearData, geolocation, error }; }; diff --git a/src/pages/Home/components/Filter/Filter.tsx b/src/pages/Home/components/Filter/Filter.tsx index f60be6f5..16b74908 100644 --- a/src/pages/Home/components/Filter/Filter.tsx +++ b/src/pages/Home/components/Filter/Filter.tsx @@ -93,7 +93,7 @@ const Filter = (props: IFilterProps) => { geolocation: Yup.object() .shape({ radiusInMeters: Yup.number().positive( - 'Raio em metros deve ser um número positivo' + 'Raio em metros deve ser positivo' ), }) .nullable(), diff --git a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx index aac691b1..84e88b98 100644 --- a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx +++ b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx @@ -5,10 +5,38 @@ import { Button } from '@/components/ui/button'; import { Slider } from '@/components/ui/slider'; import { useGeolocation } from '@/hooks'; import { ILocationFilter } from './types'; +import { getOS } from './utils'; +import { Link } from 'react-router-dom'; const MAX_PROXIMITY_IN_METERS = 50_000; const PROXIMITY_INTERVAL_IN_METERS = 500; +const LocationAdvice = () => { + const currentOs = getOS(); + + if (currentOs === 'Android') { + return ( + + Clique aqui para mais informações sobre a opção de geolocalização do + Android + + ); + } + if (currentOs === 'iOS') { + return ( + + Veja mais informações sobre a opção de geolocalização do Iphone + + ); + } + + return null; +}; + const LocationFilter = ({ geolocationFormValues, geolocationValues, @@ -85,7 +113,10 @@ const LocationFilter = ({ {Boolean(errorGeolocation) && ( <> {errorGeolocation && ( -

{errorGeolocation}

+ <> + +

{errorGeolocation}

+ )} )} @@ -97,7 +128,7 @@ const LocationFilter = ({

{Boolean(error) && (
- {error &&

{error}

} +

{error}

)}
diff --git a/src/pages/Home/components/Filter/LocationFilter/utils.ts b/src/pages/Home/components/Filter/LocationFilter/utils.ts new file mode 100644 index 00000000..7ac10547 --- /dev/null +++ b/src/pages/Home/components/Filter/LocationFilter/utils.ts @@ -0,0 +1,10 @@ +type IgetOS = 'Windows' | 'Linux' | 'Android' | 'iOS' | 'Unknown OS'; + +export function getOS(): IgetOS { + let OSName = 'Unknown OS'; + if (navigator.userAgent.indexOf('Win') != -1) OSName = 'Windows'; + if (navigator.userAgent.indexOf('Linux') != -1) OSName = 'Linux'; + if (navigator.userAgent.indexOf('Android') != -1) OSName = 'Android'; + if (navigator.userAgent.indexOf('like Mac') != -1) OSName = 'iOS'; + return OSName as IgetOS; +} From 16c075c194a82da2f0ad844daeabb1c5a91f85dd Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Wed, 15 May 2024 13:55:35 -0300 Subject: [PATCH 07/15] fix: type error of formik nested attribute --- src/pages/Home/components/Filter/Filter.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Home/components/Filter/Filter.tsx b/src/pages/Home/components/Filter/Filter.tsx index 16b74908..457e535f 100644 --- a/src/pages/Home/components/Filter/Filter.tsx +++ b/src/pages/Home/components/Filter/Filter.tsx @@ -1,6 +1,6 @@ import { useCallback, useMemo } from 'react'; import Select from 'react-select'; -import { useFormik } from 'formik'; +import { getIn, useFormik } from 'formik'; import * as Yup from 'yup'; import { LoadingScreen, SearchInput } from '@/components'; @@ -161,7 +161,7 @@ const Filter = (props: IFilterProps) => { geolocationFormValues={values?.geolocation} geolocationValues={data?.geolocation} setFieldValue={setFieldValue} - error={errors.geolocation?.radiusInMeters} + error={getIn(errors, 'geolocation.radiusInMeters')} /> Date: Thu, 16 May 2024 14:34:30 -0300 Subject: [PATCH 08/15] fix: wrong error on case --- src/hooks/useGeolocation/useGeolocation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useGeolocation/useGeolocation.tsx b/src/hooks/useGeolocation/useGeolocation.tsx index 1c6dab12..1d80615c 100644 --- a/src/hooks/useGeolocation/useGeolocation.tsx +++ b/src/hooks/useGeolocation/useGeolocation.tsx @@ -23,7 +23,7 @@ export const useGeolocation = () => { setError(GeolocationError.PERMISSION_DENIED); break; case error.POSITION_UNAVAILABLE: - setError(GeolocationError.PERMISSION_DENIED); + setError(GeolocationError.POSITION_UNAVAILABLE); break; case error.TIMEOUT: setError(GeolocationError.TIMEOUT); From b5b29690c0650bbb194a62eac1dba1bfa5022fc6 Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Thu, 16 May 2024 20:59:08 -0300 Subject: [PATCH 09/15] fix: using object literal instead of switch --- src/hooks/useGeolocation/types.ts | 9 ----- src/hooks/useGeolocation/useGeolocation.tsx | 29 ++++++++-------- .../Filter/LocationFilter/LocationFilter.tsx | 33 ++++++++----------- 3 files changed, 26 insertions(+), 45 deletions(-) diff --git a/src/hooks/useGeolocation/types.ts b/src/hooks/useGeolocation/types.ts index 250622a9..876fdf19 100644 --- a/src/hooks/useGeolocation/types.ts +++ b/src/hooks/useGeolocation/types.ts @@ -3,12 +3,3 @@ export interface IGeolocation { longitude: number; radiusInMeters?: number; } - -export const GeolocationError = { - PERMISSION_DENIED: 'É preciso liberar a permissão de geolocalização.', - POSITION_UNAVAILABLE: - 'Infelizmente não foi possível obter sua posição, talvez seu dispositivo esteja desatualizado.', - TIMEOUT: 'A requisição expirou, por favor tente novamente.', - DEFAULT: - 'Infelizmente não foi possível obter seu endereço neste dispositivo.', -}; diff --git a/src/hooks/useGeolocation/useGeolocation.tsx b/src/hooks/useGeolocation/useGeolocation.tsx index 1d80615c..1bdc4592 100644 --- a/src/hooks/useGeolocation/useGeolocation.tsx +++ b/src/hooks/useGeolocation/useGeolocation.tsx @@ -1,6 +1,6 @@ import { useState, useCallback } from 'react'; -import { GeolocationError, IGeolocation } from './types'; +import { IGeolocation } from './types'; export const useGeolocation = () => { const [geolocation, setGeolocation] = useState({ @@ -18,21 +18,18 @@ export const useGeolocation = () => { }; const showError = (error: GeolocationPositionError) => { - switch (error.code) { - case error.PERMISSION_DENIED: - setError(GeolocationError.PERMISSION_DENIED); - break; - case error.POSITION_UNAVAILABLE: - setError(GeolocationError.POSITION_UNAVAILABLE); - break; - case error.TIMEOUT: - setError(GeolocationError.TIMEOUT); - break; - - default: - setError(GeolocationError.DEFAULT); - break; - } + const errorMessages: { [key: number]: string } = { + [GeolocationPositionError.PERMISSION_DENIED]: + 'É preciso liberar a permissão de geolocalização.', + [GeolocationPositionError.POSITION_UNAVAILABLE]: + 'Infelizmente não foi possível obter sua posição, talvez seu dispositivo esteja desatualizado.', + [GeolocationPositionError.TIMEOUT]: + 'A requisição expirou, por favor tente novamente.', + }; + const errorMessage = + errorMessages[error.code] || + 'Infelizmente não foi possível obter seu endereço neste dispositivo.'; + setError(errorMessage); setIsLoading(false); }; diff --git a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx index 84e88b98..a2ef072c 100644 --- a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx +++ b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx @@ -14,27 +14,20 @@ const PROXIMITY_INTERVAL_IN_METERS = 500; const LocationAdvice = () => { const currentOs = getOS(); - if (currentOs === 'Android') { - return ( - - Clique aqui para mais informações sobre a opção de geolocalização do - Android - - ); - } - if (currentOs === 'iOS') { - return ( - - Veja mais informações sobre a opção de geolocalização do Iphone - - ); - } + const devicesLinks: { [key: string]: string } = { + ['Android']: + 'https://support.google.com/accounts/answer/3467281?hl=pt-BR#turn_on_off', + ['iOS']: 'https://support.apple.com/pt-br/102647', + }; + const currentLink = + devicesLinks[currentOs] || + 'https://support.google.com/chrome/answer/142065?hl=pt-BR&co=GENIE.Platform%3DDesktop&sjid=11531706076940529676-SA'; - return null; + return ( + + Veja mais informações sobre a opção de geolocalização do Iphone + + ); }; const LocationFilter = ({ From 1128627957aff41068e23eb03f0a1bc59d297dad Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Fri, 17 May 2024 16:48:41 -0300 Subject: [PATCH 10/15] fix: z-index of header back and dialog higher than header and menu --- src/components/Header/Header.tsx | 2 +- src/components/ui/dialog.tsx | 54 ++++++++++++++++---------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 06a8136b..9dde1265 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -17,7 +17,7 @@ const Header = React.forwardRef((props, ref) => {
, @@ -19,13 +19,13 @@ const DialogOverlay = React.forwardRef< -)) -DialogOverlay.displayName = DialogPrimitive.Overlay.displayName +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; const DialogContent = React.forwardRef< React.ElementRef, @@ -36,7 +36,7 @@ const DialogContent = React.forwardRef< -)) -DialogContent.displayName = DialogPrimitive.Content.displayName +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; const DialogHeader = ({ className, @@ -57,13 +57,13 @@ const DialogHeader = ({ }: React.HTMLAttributes) => (
-) -DialogHeader.displayName = "DialogHeader" +); +DialogHeader.displayName = 'DialogHeader'; const DialogFooter = ({ className, @@ -71,13 +71,13 @@ const DialogFooter = ({ }: React.HTMLAttributes) => (
-) -DialogFooter.displayName = "DialogFooter" +); +DialogFooter.displayName = 'DialogFooter'; const DialogTitle = React.forwardRef< React.ElementRef, @@ -86,13 +86,13 @@ const DialogTitle = React.forwardRef< -)) -DialogTitle.displayName = DialogPrimitive.Title.displayName +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; const DialogDescription = React.forwardRef< React.ElementRef, @@ -100,11 +100,11 @@ const DialogDescription = React.forwardRef< >(({ className, ...props }, ref) => ( -)) -DialogDescription.displayName = DialogPrimitive.Description.displayName +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; export { Dialog, @@ -117,4 +117,4 @@ export { DialogFooter, DialogTitle, DialogDescription, -} +}; From 53917d3925d8fe4095914bcc47ff0b46185f7cb8 Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Fri, 17 May 2024 16:49:21 -0300 Subject: [PATCH 11/15] fix: suggestions --- src/hooks/useGeolocation/useGeolocation.tsx | 5 +- src/pages/Home/components/Filter/Filter.tsx | 3 +- .../Filter/LocationFilter/LocationFilter.tsx | 128 ++++++++---------- .../components/Filter/LocationFilter/types.ts | 1 - 4 files changed, 61 insertions(+), 76 deletions(-) diff --git a/src/hooks/useGeolocation/useGeolocation.tsx b/src/hooks/useGeolocation/useGeolocation.tsx index 1bdc4592..a643287e 100644 --- a/src/hooks/useGeolocation/useGeolocation.tsx +++ b/src/hooks/useGeolocation/useGeolocation.tsx @@ -41,7 +41,10 @@ export const useGeolocation = () => { if (geolocation.latitude && geolocation.longitude) return; setIsLoading(true); - if (!window.navigator.geolocation) return; + if (!window.navigator.geolocation) { + setIsLoading(false); + return; + } window.navigator.geolocation.getCurrentPosition( (position) => showPosition(position), diff --git a/src/pages/Home/components/Filter/Filter.tsx b/src/pages/Home/components/Filter/Filter.tsx index 73c82a53..8c74d5bf 100644 --- a/src/pages/Home/components/Filter/Filter.tsx +++ b/src/pages/Home/components/Filter/Filter.tsx @@ -176,8 +176,7 @@ const Filter = (props: IFilterProps) => {
diff --git a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx index a2ef072c..01f2d348 100644 --- a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx +++ b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx @@ -14,7 +14,7 @@ const PROXIMITY_INTERVAL_IN_METERS = 500; const LocationAdvice = () => { const currentOs = getOS(); - const devicesLinks: { [key: string]: string } = { + const devicesLinks: Record = { ['Android']: 'https://support.google.com/accounts/answer/3467281?hl=pt-BR#turn_on_off', ['iOS']: 'https://support.apple.com/pt-br/102647', @@ -25,13 +25,12 @@ const LocationAdvice = () => { return ( - Veja mais informações sobre a opção de geolocalização do Iphone + Veja mais informações sobre a opção de geolocalização ); }; const LocationFilter = ({ - geolocationFormValues, geolocationValues, setFieldValue, error, @@ -43,15 +42,10 @@ const LocationFilter = ({ error: errorGeolocation, } = useGeolocation(); const [isProximityChecked, setIsProximityChecked] = useState( - (Boolean(geolocationValues?.latitude) && - Boolean(geolocationValues?.longitude)) || - (Boolean(geolocationFormValues?.latitude) && - Boolean(geolocationFormValues?.longitude)) + Boolean(geolocationValues?.latitude) && + Boolean(geolocationValues?.longitude) ); - const normalizedRadiusMeters = - geolocationFormValues?.radiusInMeters ?? - geolocationValues?.radiusInMeters ?? - 0; + const normalizedRadiusMeters = geolocationValues?.radiusInMeters ?? 0; useEffect(() => { if (!isProximityChecked) return; @@ -99,78 +93,68 @@ const LocationFilter = ({ Filtro por proximidade - {Boolean(isLoading) && ( + {isLoading && ( )}
{Boolean(errorGeolocation) && ( <> - {errorGeolocation && ( - <> - -

{errorGeolocation}

- - )} + +

{errorGeolocation}

)} {showFilter && ( - <> -
-

- Selecione o raio máximo de abrigos na região(KM's ao redor) -

- {Boolean(error) && ( -
-

{error}

-
- )} -
- - - {normalizedRadiusMeters / 1000} km - - +
+

+ Selecione o raio máximo de abrigos na região(KM's ao redor) +

+ {Boolean(error) && ( +
+

{error}

- { - setFieldValue('geolocation.radiusInMeters', value[0]); + )} +
+ + + {normalizedRadiusMeters / 1000} km + +
- + { + setFieldValue('geolocation.radiusInMeters', value[0]); + }} + name="geolocation.radiusInMeters" + className="" + /> +
)}
diff --git a/src/pages/Home/components/Filter/LocationFilter/types.ts b/src/pages/Home/components/Filter/LocationFilter/types.ts index 0e2f5c13..f3123db7 100644 --- a/src/pages/Home/components/Filter/LocationFilter/types.ts +++ b/src/pages/Home/components/Filter/LocationFilter/types.ts @@ -1,7 +1,6 @@ import { IGeolocation } from '@/hooks/useGeolocation/types'; export interface ILocationFilter { - geolocationFormValues?: IGeolocation; geolocationValues?: IGeolocation; setFieldValue: any; error?: string; From 76800da6c8a2d46b4cf2d4a4fd9b000b408fa034 Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Fri, 17 May 2024 18:21:13 -0300 Subject: [PATCH 12/15] fix: minor recomendations and not necessary state change --- src/hooks/useGeolocation/useGeolocation.tsx | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/hooks/useGeolocation/useGeolocation.tsx b/src/hooks/useGeolocation/useGeolocation.tsx index a643287e..9439e9a8 100644 --- a/src/hooks/useGeolocation/useGeolocation.tsx +++ b/src/hooks/useGeolocation/useGeolocation.tsx @@ -40,17 +40,12 @@ export const useGeolocation = () => { const getLocation = useCallback(() => { if (geolocation.latitude && geolocation.longitude) return; + if (!window.navigator.geolocation) return; setIsLoading(true); - if (!window.navigator.geolocation) { - setIsLoading(false); - return; - } - - window.navigator.geolocation.getCurrentPosition( - (position) => showPosition(position), - (error) => showError(error), - { enableHighAccuracy: true } - ); + + window.navigator.geolocation.getCurrentPosition(showPosition, showError, { + enableHighAccuracy: true, + }); }, [geolocation.latitude, geolocation.longitude]); return { isLoading, getLocation, clearData, geolocation, error }; From 3a1b66580d414bd05f38da809bdde70469b54f15 Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Sat, 18 May 2024 18:47:29 -0300 Subject: [PATCH 13/15] feat: new screen specs using switch and reduced slider options --- package-lock.json | 30 +++++++ package.json | 1 + src/components/ui/switch.tsx | 27 ++++++ src/pages/Home/components/Filter/Filter.tsx | 3 +- .../Filter/LocationFilter/LocationFilter.tsx | 84 +++++++++---------- 5 files changed, 100 insertions(+), 45 deletions(-) create mode 100644 src/components/ui/switch.tsx diff --git a/package-lock.json b/package-lock.json index e17a050a..ad8f0edd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-tooltip": "^1.0.7", "axios": "^1.6.8", @@ -1880,6 +1881,35 @@ } } }, + "node_modules/@radix-ui/react-switch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.0.3.tgz", + "integrity": "sha512-mxm87F88HyHztsI7N+ZUmEoARGkC22YVW5CaC+Byc+HRpuvCrOBPTAnXgf+tZ/7i0Sg/eOePGdMhUKhPaQEqow==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-controllable-state": "1.0.1", + "@radix-ui/react-use-previous": "1.0.1", + "@radix-ui/react-use-size": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-toast": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.1.5.tgz", diff --git a/package.json b/package.json index e4922119..877a8319 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-tooltip": "^1.0.7", "axios": "^1.6.8", diff --git a/src/components/ui/switch.tsx b/src/components/ui/switch.tsx new file mode 100644 index 00000000..ede76422 --- /dev/null +++ b/src/components/ui/switch.tsx @@ -0,0 +1,27 @@ +import * as React from 'react'; +import * as SwitchPrimitives from '@radix-ui/react-switch'; + +import { cn } from '@/lib/utils'; + +const Switch = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +Switch.displayName = SwitchPrimitives.Root.displayName; + +export { Switch }; diff --git a/src/pages/Home/components/Filter/Filter.tsx b/src/pages/Home/components/Filter/Filter.tsx index 8c74d5bf..ebe70816 100644 --- a/src/pages/Home/components/Filter/Filter.tsx +++ b/src/pages/Home/components/Filter/Filter.tsx @@ -166,7 +166,7 @@ const Filter = (props: IFilterProps) => {
-
+
@@ -174,7 +174,6 @@ const Filter = (props: IFilterProps) => { } />
-
-
- +
+ { + // const { checked } = event.target; + setIsProximityChecked(checked); + if (checked) { + getLocation(); + return; + } + setFieldValue('geolocation.radiusInMeters', undefined); + setFieldValue('geolocation.latitude', undefined); + setFieldValue('geolocation.longitude', undefined); + }} + > + {isLoading && ( )}
+
{Boolean(errorGeolocation) && ( <> @@ -105,14 +103,12 @@ const LocationFilter = ({ )} {showFilter && (
-

- Selecione o raio máximo de abrigos na região(KM's ao redor) -

- {Boolean(error) && ( -
-

{error}

+
+
Proximidade do abrigo
+
+ {normalizedRadiusMeters / 1000} km
- )} +
- - {normalizedRadiusMeters / 1000} km - + { + setFieldValue('geolocation.radiusInMeters', value[0]); + }} + name="geolocation.radiusInMeters" + className="" + />
- { - setFieldValue('geolocation.radiusInMeters', value[0]); - }} - name="geolocation.radiusInMeters" - className="" - /> + {Boolean(error) && ( +
+

{error}

+
+ )}
)}
From fe3e8244870ff7819242d5982f55c5ef0bdd0eb2 Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Sat, 18 May 2024 18:53:07 -0300 Subject: [PATCH 14/15] fix: text color to blue --- .../Home/components/Filter/LocationFilter/LocationFilter.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx index e0052212..a58b7335 100644 --- a/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx +++ b/src/pages/Home/components/Filter/LocationFilter/LocationFilter.tsx @@ -119,7 +119,7 @@ const LocationFilter = ({ ); setFieldValue('geolocation.radiusInMeters', newValue); }} - className="flex bg-white text-black hover:bg-white rounded-full border-blue-600 border-2 p-0 m-0 hover:opacity-80 transition-colors duration-800 self-auto h-6 aspect-square" + className="flex bg-white text-blue-600 hover:bg-white rounded-full border-blue-600 border-2 p-0 m-0 hover:opacity-80 transition-colors duration-800 self-auto h-6 aspect-square" > - @@ -142,7 +142,7 @@ const LocationFilter = ({ ); setFieldValue('geolocation.radiusInMeters', newValue); }} - className="flex bg-white text-black hover:bg-white rounded-full border-blue-600 border-2 p-0 m-0 hover:opacity-80 transition-colors duration-800 self-auto h-6 aspect-square" + className="flex bg-white text-blue-600 hover:bg-white rounded-full border-blue-600 border-2 p-0 m-0 hover:opacity-80 transition-colors duration-800 self-auto h-6 aspect-square" > + From 2fe578b5aa69d859641cd03148fd6985b17f85ac Mon Sep 17 00:00:00 2001 From: kelvinsb Date: Sat, 18 May 2024 21:22:27 -0300 Subject: [PATCH 15/15] fix: geolocation error --- src/pages/Home/components/Filter/Filter.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/Home/components/Filter/Filter.tsx b/src/pages/Home/components/Filter/Filter.tsx index ebe70816..6b814c63 100644 --- a/src/pages/Home/components/Filter/Filter.tsx +++ b/src/pages/Home/components/Filter/Filter.tsx @@ -95,9 +95,7 @@ const Filter = (props: IFilterProps) => { search: Yup.string(), geolocation: Yup.object() .shape({ - radiusInMeters: Yup.number().positive( - 'Raio em metros deve ser positivo' - ), + radiusInMeters: Yup.number().positive('Raio deve ser positivo'), }) .nullable(), }),