From 8adfc4ae57dbc73156384bef892f3e6d2fb99fc6 Mon Sep 17 00:00:00 2001 From: AlexDyakonov Date: Sun, 1 Dec 2024 11:44:19 +0300 Subject: [PATCH 1/2] added filters --- src/pages/find.page.tsx | 102 ++++++++++++++++++++++++------- src/shared/api/additional.api.ts | 38 ++++++++++++ 2 files changed, 118 insertions(+), 22 deletions(-) create mode 100644 src/shared/api/additional.api.ts diff --git a/src/pages/find.page.tsx b/src/pages/find.page.tsx index 637e4bd..ad4647d 100644 --- a/src/pages/find.page.tsx +++ b/src/pages/find.page.tsx @@ -1,17 +1,35 @@ -import { useState, useEffect } from 'react'; -import { getAllPeople } from '@/shared/api/people.api'; -import { searchPeople } from '@/shared/api/people.api'; +import { useState, useEffect, useCallback } from 'react'; +import { getAllPeople } from '@/shared/api/people.api'; // Для получения всех людей +import { searchPeople } from '@/shared/api/people.api'; // Для поиска по запросу +import { getAllDepartments, getAllDivisions } from '@/shared/api/additional.api'; // Для фильтров import { Person } from '@/shared/interfaces/person.interface'; -import { useSelectedStore } from '@/shared/store/selected.store'; export const FindPage = () => { const [searchTerm, setSearchTerm] = useState(''); const [people, setPeople] = useState([]); const [allPeople, setAllPeople] = useState([]); + const [departments, setDepartments] = useState([]); + const [divisions, setDivisions] = useState([]); + const [selectedDepartment, setSelectedDepartment] = useState(''); + const [selectedDivision, setSelectedDivision] = useState(''); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); - const { setSelected } = useSelectedStore(); + useEffect(() => { + const fetchDepartmentsAndDivisions = async () => { + try { + const fetchedDepartments = await getAllDepartments(); + const fetchedDivisions = await getAllDivisions(); + setDepartments(fetchedDepartments); + setDivisions(fetchedDivisions); + } catch (err) { + setError('Не удалось загрузить фильтры'); + console.error(err); + } + }; + + fetchDepartmentsAndDivisions(); + }, []); useEffect(() => { const fetchAllPeople = async () => { @@ -59,54 +77,94 @@ export const FindPage = () => { } }; + const handleFilterChange = useCallback(() => { + const filteredPeople = allPeople.filter((person) => { + const matchesDepartment = + selectedDepartment ? person.department === selectedDepartment : true; + const matchesDivision = + selectedDivision ? person.division === selectedDivision : true; + return matchesDepartment && matchesDivision; + }); + setPeople(filteredPeople); + }, [selectedDepartment, selectedDivision, allPeople]); + + useEffect(() => { + handleFilterChange(); + }, [selectedDepartment, selectedDivision, handleFilterChange]); + return ( -
-
-
+
+
+
-
+
+ + + +
+ +
{loading ? (
Загрузка...
) : error ? (
{error}
) : ( -
+
{people.length > 0 ? ( people.map((person) => (
setSelected(person)} - className='bg-white p-4 rounded-xl border flex flex-col items-center justify-center text-center space-y-3' + className="bg-white p-4 rounded-xl shadow-lg flex flex-col items-center justify-center text-center space-y-3" > {`${person.name} -

+

{person.name} {person.surname}

-

{person.jobtitle}

+

{person.jobtitle}

{person.division && ( -

- Отдел: {person.division} -

+

Отдел: {person.division}

)}
)) diff --git a/src/shared/api/additional.api.ts b/src/shared/api/additional.api.ts new file mode 100644 index 0000000..6b37070 --- /dev/null +++ b/src/shared/api/additional.api.ts @@ -0,0 +1,38 @@ +import { API_URL } from '../constants'; + +export const getAllDepartments = async (): Promise => { + try { + const response = await fetch( + `${API_URL}/persons/departments` + ); + + if (!response.ok) { + throw new Error('Failed to fetch departments'); + } + + const departments: string[] = await response.json(); + return departments; + } catch (error) { + console.error('Error fetching departments:', error); + throw error; + } +}; + +export const getAllDivisions = async (): Promise => { + try { + const response = await fetch( + `${API_URL}/persons/divisions` + ); + + if (!response.ok) { + throw new Error('Failed to fetch divisions'); + } + + const divisions: string[] = await response.json(); + return divisions; + } catch (error) { + console.error('Error fetching divisions:', error); + throw error; + } + }; + \ No newline at end of file From aabc2189db6a38686a71752538380dfef2138b07 Mon Sep 17 00:00:00 2001 From: AlexDyakonov Date: Sun, 1 Dec 2024 12:15:19 +0300 Subject: [PATCH 2/2] added filters --- package.json | 1 + src/components/ui/select.tsx | 156 +++++++++++++++++++++++++++++++++++ src/pages/find.page.tsx | 106 +++++++++++++----------- yarn.lock | 133 +++++++++++++++++++++++++++++ 4 files changed, 346 insertions(+), 50 deletions(-) create mode 100644 src/components/ui/select.tsx diff --git a/package.json b/package.json index a3a494a..c2fdf80 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-select": "^2.1.2", "@radix-ui/react-slot": "^1.1.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx new file mode 100644 index 0000000..12836ea --- /dev/null +++ b/src/components/ui/select.tsx @@ -0,0 +1,156 @@ +import * as React from "react" +import * as SelectPrimitive from "@radix-ui/react-select" +import { cn } from "@/lib/utils" +import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "@radix-ui/react-icons" + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1", + className + )} + {...props} + > + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = "popper", ...props }, ref) => ( + + + + + {children} + + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +} diff --git a/src/pages/find.page.tsx b/src/pages/find.page.tsx index ad4647d..57edc56 100644 --- a/src/pages/find.page.tsx +++ b/src/pages/find.page.tsx @@ -1,8 +1,10 @@ -import { useState, useEffect, useCallback } from 'react'; -import { getAllPeople } from '@/shared/api/people.api'; // Для получения всех людей -import { searchPeople } from '@/shared/api/people.api'; // Для поиска по запросу -import { getAllDepartments, getAllDivisions } from '@/shared/api/additional.api'; // Для фильтров +import { useState, useEffect } from 'react'; +import { getAllPeople } from '@/shared/api/people.api'; +import { searchPeople } from '@/shared/api/people.api'; import { Person } from '@/shared/interfaces/person.interface'; +import { useSelectedStore } from '@/shared/store/selected.store'; +import { getAllDepartments, getAllDivisions } from '@/shared/api/additional.api'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; // Импорт компонентов из ShadCN UI export const FindPage = () => { const [searchTerm, setSearchTerm] = useState(''); @@ -15,6 +17,8 @@ export const FindPage = () => { const [loading, setLoading] = useState(false); const [error, setError] = useState(''); + const { setSelected } = useSelectedStore(); + useEffect(() => { const fetchDepartmentsAndDivisions = async () => { try { @@ -54,14 +58,9 @@ export const FindPage = () => { }; const handleSearchClick = async () => { - if (searchTerm.trim() === '') { - setPeople(allPeople); - return; - } - setLoading(true); try { - const results = await searchPeople(searchTerm); + const results = searchTerm.trim() === '' ? allPeople : await searchPeople(searchTerm); setPeople(results); } catch (err) { setError('Не удалось выполнить поиск'); @@ -77,33 +76,37 @@ export const FindPage = () => { } }; - const handleFilterChange = useCallback(() => { + const handleFilterChange = () => { const filteredPeople = allPeople.filter((person) => { const matchesDepartment = - selectedDepartment ? person.department === selectedDepartment : true; + selectedDepartment && selectedDepartment !== 'Все департаменты' + ? person.department === selectedDepartment + : true; const matchesDivision = - selectedDivision ? person.division === selectedDivision : true; + selectedDivision && selectedDivision !== 'Все подразделения' + ? person.division === selectedDivision + : true; return matchesDepartment && matchesDivision; }); setPeople(filteredPeople); - }, [selectedDepartment, selectedDivision, allPeople]); + }; useEffect(() => { handleFilterChange(); - }, [selectedDepartment, selectedDivision, handleFilterChange]); + }, [selectedDepartment, selectedDivision, allPeople]); return (
- +
- - - + + +
@@ -151,12 +156,13 @@ export const FindPage = () => { people.map((person) => (
setSelected(person)} + className="bg-white p-4 rounded-xl border flex flex-col items-center justify-center text-center space-y-3" > {`${person.name}

{person.name} {person.surname} diff --git a/yarn.lock b/yarn.lock index 6b856c5..9d172b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -199,6 +199,33 @@ dependencies: levn "^0.4.1" +"@floating-ui/core@^1.6.0": + version "1.6.8" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.8.tgz#aa43561be075815879305965020f492cdb43da12" + integrity sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA== + dependencies: + "@floating-ui/utils" "^0.2.8" + +"@floating-ui/dom@^1.0.0": + version "1.6.12" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.12.tgz#6333dcb5a8ead3b2bf82f33d6bc410e95f54e556" + integrity sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w== + dependencies: + "@floating-ui/core" "^1.6.0" + "@floating-ui/utils" "^0.2.8" + +"@floating-ui/react-dom@^2.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.2.tgz#a1349bbf6a0e5cb5ded55d023766f20a4d439a31" + integrity sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A== + dependencies: + "@floating-ui/dom" "^1.0.0" + +"@floating-ui/utils@^0.2.8": + version "0.2.8" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62" + integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== + "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" @@ -279,6 +306,11 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@radix-ui/number@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.0.tgz#1e95610461a09cdf8bb05c152e76ca1278d5da46" + integrity sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ== + "@radix-ui/primitive@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd" @@ -291,6 +323,23 @@ resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.0.tgz#42ef83b3b56dccad5d703ae8c42919a68798bbe2" integrity sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA== +"@radix-ui/react-arrow@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz#744f388182d360b86285217e43b6c63633f39e7a" + integrity sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw== + dependencies: + "@radix-ui/react-primitive" "2.0.0" + +"@radix-ui/react-collection@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.0.tgz#f18af78e46454a2360d103c2251773028b7724ed" + integrity sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw== + dependencies: + "@radix-ui/react-compose-refs" "1.1.0" + "@radix-ui/react-context" "1.1.0" + "@radix-ui/react-primitive" "2.0.0" + "@radix-ui/react-slot" "1.1.0" + "@radix-ui/react-compose-refs@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989" @@ -310,6 +359,11 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-context@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.0.tgz#6df8d983546cfd1999c8512f3a8ad85a6e7fcee8" + integrity sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A== + "@radix-ui/react-context@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.1.tgz#82074aa83a472353bb22e86f11bcbd1c61c4c71a" @@ -356,6 +410,11 @@ aria-hidden "^1.1.1" react-remove-scroll "2.6.0" +"@radix-ui/react-direction@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.0.tgz#a7d39855f4d077adc2a1922f9c353c5977a09cdc" + integrity sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg== + "@radix-ui/react-dismissable-layer@1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4" @@ -437,6 +496,22 @@ dependencies: "@radix-ui/react-primitive" "2.0.0" +"@radix-ui/react-popper@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.2.0.tgz#a3e500193d144fe2d8f5d5e60e393d64111f2a7a" + integrity sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg== + dependencies: + "@floating-ui/react-dom" "^2.0.0" + "@radix-ui/react-arrow" "1.1.0" + "@radix-ui/react-compose-refs" "1.1.0" + "@radix-ui/react-context" "1.1.0" + "@radix-ui/react-primitive" "2.0.0" + "@radix-ui/react-use-callback-ref" "1.1.0" + "@radix-ui/react-use-layout-effect" "1.1.0" + "@radix-ui/react-use-rect" "1.1.0" + "@radix-ui/react-use-size" "1.1.0" + "@radix-ui/rect" "1.1.0" + "@radix-ui/react-portal@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15" @@ -485,6 +560,33 @@ dependencies: "@radix-ui/react-slot" "1.1.0" +"@radix-ui/react-select@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-2.1.2.tgz#2346e118966db793940f6a866fd4cc5db2cc275e" + integrity sha512-rZJtWmorC7dFRi0owDmoijm6nSJH1tVw64QGiNIZ9PNLyBDtG+iAq+XGsya052At4BfarzY/Dhv9wrrUr6IMZA== + dependencies: + "@radix-ui/number" "1.1.0" + "@radix-ui/primitive" "1.1.0" + "@radix-ui/react-collection" "1.1.0" + "@radix-ui/react-compose-refs" "1.1.0" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-direction" "1.1.0" + "@radix-ui/react-dismissable-layer" "1.1.1" + "@radix-ui/react-focus-guards" "1.1.1" + "@radix-ui/react-focus-scope" "1.1.0" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-popper" "1.2.0" + "@radix-ui/react-portal" "1.1.2" + "@radix-ui/react-primitive" "2.0.0" + "@radix-ui/react-slot" "1.1.0" + "@radix-ui/react-use-callback-ref" "1.1.0" + "@radix-ui/react-use-controllable-state" "1.1.0" + "@radix-ui/react-use-layout-effect" "1.1.0" + "@radix-ui/react-use-previous" "1.1.0" + "@radix-ui/react-visually-hidden" "1.1.0" + aria-hidden "^1.1.1" + react-remove-scroll "2.6.0" + "@radix-ui/react-slot@1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" @@ -554,6 +656,37 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz#3c2c8ce04827b26a39e442ff4888d9212268bd27" integrity sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w== +"@radix-ui/react-use-previous@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz#d4dd37b05520f1d996a384eb469320c2ada8377c" + integrity sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og== + +"@radix-ui/react-use-rect@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz#13b25b913bd3e3987cc9b073a1a164bb1cf47b88" + integrity sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ== + dependencies: + "@radix-ui/rect" "1.1.0" + +"@radix-ui/react-use-size@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz#b4dba7fbd3882ee09e8d2a44a3eed3a7e555246b" + integrity sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.0" + +"@radix-ui/react-visually-hidden@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz#ad47a8572580f7034b3807c8e6740cd41038a5a2" + integrity sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ== + dependencies: + "@radix-ui/react-primitive" "2.0.0" + +"@radix-ui/rect@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.0.tgz#f817d1d3265ac5415dadc67edab30ae196696438" + integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg== + "@rollup/rollup-android-arm-eabi@4.22.4": version "4.22.4" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz#8b613b9725e8f9479d142970b106b6ae878610d5"