Skip to content

Commit

Permalink
Release 0.0.1 (#135)
Browse files Browse the repository at this point in the history
* [fix] Config readme

* wip: loading

* Delete yarn.lock

* refact: created shelter list view component in home page

* Fix: mobile UI has broken for mobile devices (#22)

*Fix: mobile UI has broken for mobile devices

* fix: remove chip as fixed as no wrap property

* chore: add shelter card clickable

* chore: remove Fragment component

* build: add set sm as max mobile dimension
          sm: 425px

* style: add responsive layout

* refactor: filter page

* fix: priority

* fix: filter parameters

* fix: fixed volunteer supply that had been fulfilled displaying on shelter page

* fix: improve readability

* feat: hidden filter button if filter is empty

* feat: cache in axios request

* fix: cache search params

* feat: cache clean on searchs

* wip: donation tags

* fix: clean search params

* Update README.md

[fix] Retirando a seção Funcionalidades e Backlog

* fix: donation tags / componentized the urgent supplies section

* fix: removed empty shelter tags empty row

* feat: full edit shelter and improved interface of pet friendly in shelter page

* refact: add live link and tech stack to readme

* Fix/develop bugs (#90)

* fix: cache bug (invalite cache on create/update operation)

* feat: added update many shelter supplies and admin rule

* Add license (#81)

Closes #65.

* fix: app port (#80)

* docs: added shadcn/ui reference

* fix for volunteer shelter title (#95)

* treat contact link as a proper link

* simplified href

* docs: add discord link on readme

* Normalizes search string in supply filter so it ignores accents (#125)

* normalized search string to ignore accents

* revert removed button

* add a copy to clipboard button to PIX and contact info (#124)

* add a copy to clipboard button to PIX and contact info

* use && operator instead of ternary

* Substitui onClick e useNavigate por <Link> para melhorar acessibilidade (#128)

* replaced navigate in favour of html link and added card hover

* fixed lint warnings

* fix: change shelter title style (#106)

Prevents badge misalignment on very large titles

* Add new feature and creating LoadingSkeleton (#115)

* Add new feature and creating LoadingSkeleton

---------

Co-authored-by: helenapaixao <[email protected]>
Co-authored-by: José Fagundes <[email protected]>
Co-authored-by: Luccas Specht <[email protected]>
Co-authored-by: MatheusDubin <[email protected]>
Co-authored-by: danmqs <[email protected]>
Co-authored-by: Giovanni Bassi <[email protected]>
Co-authored-by: Felipe Monteiro <[email protected]>
Co-authored-by: André Ferraz <[email protected]>
Co-authored-by: Sombrio <[email protected]>
Co-authored-by: Daniel Marques <[email protected]>
Co-authored-by: Matheus Dubin Da Silveira <[email protected]>
Co-authored-by: Miguel Dalberto <[email protected]>
Co-authored-by: Pablo A. Maximo <[email protected]>
Co-authored-by: Marcos Nascimento <[email protected]>
  • Loading branch information
15 people authored May 14, 2024
1 parent 3d3f437 commit 4e0d9c0
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 82 deletions.
31 changes: 12 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

Este projeto é o frontend de um aplicativo destinado a auxiliar na organização e distribuição de suprimentos, além de coordenar voluntários durante os alagamentos no Rio Grande do Sul. A aplicação visa conectar pessoas afetadas pelas enchentes com recursos essenciais e voluntários dispostos a ajudar.

## Acesso à Aplicação

[SOS Rio Grande do Sul](https://sos-rs.com/)
[Discord](https://discord.gg/eJTuannsd6)

## Sobre o Projeto

O objetivo deste aplicativo é facilitar uma resposta rápida e eficiente em situações de emergência causadas por enchentes, promovendo a colaboração e o apoio mútuo entre a comunidade e organizações de ajuda.
Expand All @@ -10,32 +15,20 @@ O objetivo deste aplicativo é facilitar uma resposta rápida e eficiente em sit

Este frontend foi desenvolvido utilizando as seguintes tecnologias:

- **React**: Uma biblioteca JavaScript para construir interfaces de usuário.

## Funcionalidades e Backlog

O app inclui as seguintes funcionalidades:

- [x] **Cadastro de Itens de suprimentos**: Permite que voluntários se inscrevam para ajudar.
- [x] **Busca de abrigos**: Gerencia a logística de distribuição de suprimentos para as áreas mais necessitadas.
- [x] **Alteração de necessidades de abrigos**: Exibe um mapa das áreas afetadas e pontos de coleta de suprimentos.
- [ ] **Cadastro de abrigos**: Criar tela para cadastro de abrigos (Nome, endereço, capacidade, vagas, aceita pets) e colocar pendende de aprovação.
- [ ] **Alteração de abrigos**: Pemitir alterar quantidade de vagas disponívies, se aceita pet ou endereço.
- [ ] **Cadastro de usuários**: Criar tela de cadastro (nome, telefone, senha) e login.
- [ ] **Filtro por item e por cidade**: Opção de filtrar abrigos por cidade ou que precisam de algum item específico.
- [ ] **Alterar ordenação**: Trocar a ordenação atual para ordenação por última atualização.
- [ ] **Adicionar mapa de abrigos**: Criar uma tela com um mapa e todos os abrigos. Verificar a posibilidade de usar geolocation para mostrar a posição do usuário no mapa.

- [**React**](https://react.dev/): Uma biblioteca JavaScript para construir interfaces de usuário.
- [**Vite**](https://vitejs.dev/guide/): Uma ferramenta de build com servidor de desenvolvimento.
- [**Tailwind CSS**](https://tailwindcss.com/docs/installation): Framework CSS baseado em classes utilitárias.
- [**shadcn/ui**](https://ui.shadcn.com/docs): Coleção de componentes reutilizáveis, baseado em Tailwind.

Para executar o frontend do aplicativo em seu ambiente local, siga os passos abaixo:

1. Clone o repositório:
```
git clone https://github.com/seuusuario/projeto-enchentes-frontend.git
git clone https://github.com/SOS-RS/frontend
```
2. Entre no diretório do projeto:
```
cd projeto-enchentes-frontend
cd frontend
```
3. Instale as dependências:
```
Expand All @@ -53,7 +46,7 @@ Contribuições são muito bem-vindas! Se você tem interesse em ajudar a melhor

1. Faça um fork do repositório.
2. Crie uma branch para sua feature (`git checkout -b feature/MinhaFeature`).
3. Faça seus commits (`git commit -am 'Adicionando uma nova feature'`).
3. Faça seus commits (`git commit -m 'Adicionando uma nova feature'`).
4. Faça push para a branch (`git push origin feature/MinhaFeature`).
5. Abra um Pull Request.

Expand Down
2 changes: 2 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="manifest" href="/site.webmanifest">
<link rel="canonical" href="https://sos-rs.com/" />

<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" />
<title>SOS - Rio Grande do Sul</title>
Expand Down
2 changes: 2 additions & 0 deletions src/components/CardAboutShelter/CardAboutShelter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ const CardAboutShelter = (props: ICardAboutShelter) => {
value={
check(shelter.contact) ? `${shelter.contact}` : 'Não informado'
}
clipboardButton={check(shelter.contact)}
/>
<InfoRow
icon={<Landmark />}
label="Chave Pix:"
value={check(shelter.pix) ? `${shelter.pix}` : 'Não informado'}
clipboardButton={check(shelter.pix)}
/>
</div>
</Card>
Expand Down
18 changes: 14 additions & 4 deletions src/components/CardAboutShelter/components/InfoRow/InfoRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import { IInfoRowProps } from './types';

const InfoRow = React.forwardRef<HTMLDivElement, IInfoRowProps>(
(props, ref) => {
const { icon, label, value, className = '', ...rest } = props;
const { icon, label, value, clipboardButton = false, className = '', ...rest } = props;
const isLink = value?.startsWith('http');
const ValueComp = !value ? (
<Fragment />
) : isLink ? (
<a
<a href={value} target='_blank'
className="text-blue-500 break-all cursor-pointer hover:underline"
onClick={() => window.open(value, '_blank')}
>
{value}
</a>
Expand All @@ -36,7 +35,18 @@ const InfoRow = React.forwardRef<HTMLDivElement, IInfoRowProps>(
<span className={cn('font-normal', value ? 'text-nowrap' : '')}>
{label}
</span>
<span className="md:flex">{ValueComp}</span>
<span className="md:flex">
{ValueComp}
{clipboardButton && value && (
<div
className="text-blue-600 mx-2 hover:cursor-pointer active:text-blue-800"
onClick={() => navigator.clipboard.writeText(value)}
>
copiar
</div>
)}
</span>

</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export interface IInfoRowProps extends React.ComponentPropsWithoutRef<'div'> {
label: React.ReactNode;
value?: string;
icon: React.ReactNode;
clipboardButton?: boolean;
}
46 changes: 46 additions & 0 deletions src/components/LoadingSkeleton/LoadingSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
type LoadingSkeletonProps = {
amountItems: number
}

const LoadingSkeleton = ({ amountItems }: LoadingSkeletonProps) => {
return (
<div className="w-full">
<ul className="grid grid-cols-1 gap-5 mt-4">
{Array.from({length: amountItems,}).map((_, index) => (
<li key={index} className="p-4 w-full border-2 border-border rounded-md space-y-3">
<div className="flex justify-between items-center space-x-2">
<div className="animate-pulse h-10 bg-[#ccc] rounded-md w-full max-w-sm" />
<div className="animate-pulse h-10 bg-[#ccc] rounded-md w-10" />
</div>

<div className="animate-pulse h-10 bg-[#ccc] rounded-md w-full max-w-xs" />

<div className="border-b border-[#ccc] opacity-25"/>

<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 md:grid-cols-4 gap-4 mt-5">
{Array.from({length: 7}).map((_, index) => (
<div
key={index}
className="animate-pulse h-8 bg-[#ccc] rounded-full w-full"
/>
))}
</div>

<div className="border-b border-[#ccc] opacity-25"/>

<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 md:grid-cols-4 gap-4 mt-5">
{Array.from({length: 7}).map((_, index) => (
<div
key={index}
className="animate-pulse h-8 bg-[#ccc] rounded-full w-full"
/>
))}
</div>
</li>
))}
</ul>
</div>
)
}

export { LoadingSkeleton }
3 changes: 3 additions & 0 deletions src/components/LoadingSkeleton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { LoadingSkeleton } from "./LoadingSkeleton";

export { LoadingSkeleton }
3 changes: 2 additions & 1 deletion src/pages/EditShelterSupply/EditShelterSupply.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ const EditShelterSupply = () => {
if (v) {
setFilteredSupplies(
supplies.filter((s) =>
s.name.toLowerCase().includes(v.toLowerCase())
s.name.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '')
.includes(v.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, ''))
)
);
} else setFilteredSupplies(supplies);
Expand Down
4 changes: 1 addition & 3 deletions src/pages/Home/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useContext, useMemo, useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useSearchParams } from 'react-router-dom';
import { RotateCw, LogOutIcon, PlusIcon } from 'lucide-react';
import qs from 'qs';

Expand Down Expand Up @@ -48,7 +48,6 @@ const Home = () => {
},
[]
);
const navigate = useNavigate();

const clearSearch = useCallback(() => {
setSearch('');
Expand Down Expand Up @@ -161,7 +160,6 @@ const Home = () => {
setFilterData((prev) => ({ ...prev, search: v }));
setSearch(v);
}}
onSelectShelter={(s) => navigate(`/abrigo/${s.id}`)}
hasMoreItems={hasMore}
onOpenModal={() => setOpenModal(true)}
onClearSearch={clearSearch}
Expand Down
96 changes: 47 additions & 49 deletions src/pages/Home/components/ShelterListItem/ShelterListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useMemo } from 'react';
import { format } from 'date-fns';
import { useNavigate } from 'react-router-dom';
import { Link } from 'react-router-dom';
import { ChevronRight } from 'lucide-react';

import {
Expand All @@ -20,9 +20,8 @@ import { IUseSheltersDataSupplyData } from '@/hooks/useShelters/types';
import { ShelterSupplyCategoryRow } from '../ShelterSupplyCategoryRow';

const ShelterListItem = (props: IShelterListItemProps) => {
const { data, onClick } = props;
const { data } = props;
const { capacity, shelteredPeople } = data;
const navigate = useNavigate();
const { availability, className: availabilityClassName } =
useMemo<IShelterAvailabilityProps>(
() => getAvailabilityProps(capacity, shelteredPeople),
Expand All @@ -42,53 +41,52 @@ const ShelterListItem = (props: IShelterListItemProps) => {
}, []);

return (
<div className="flex flex-col p-4 w-full border-2 border-border rounded-md gap-1 relative">
<Button size="sm" variant="ghost" className="absolute top-4 right-4">
<ChevronRight
className="h-5 w-5"
onClick={() => navigate(`/abrigo/${data.id}`)}
/>
</Button>
<div
className="flex items-center gap-1"
onClick={() => navigate(`/abrigo/${data.id}`)}
>
<h3
className="font-semibold text-lg hover:cursor-pointer hover:text-slate-500"
onClick={onClick}
>
{data.name}
</h3>
{data.verified && <VerifiedBadge />}
<Link to={`/abrigo/${data.id}`} target="_blank">
<div className="flex flex-col p-4 w-full border-2 border-border rounded-md gap-1 relative hover:bg-accent">
<div className="inline-flex justify-between">
<div className="flex flex-row items-center gap-1">
<h3 className="font-semibold text-lg h-full hover:cursor-pointer hover:text-slate-500">
{data.name}
</h3>
{data.verified && (
<div className="h-full pt-1">
<VerifiedBadge />
</div>
)}
</div>
<Button size="sm" variant="ghost">
<ChevronRight className="h-5 w-5" />
</Button>
</div>
<h6 className={cn('font-semibold text-md', availabilityClassName)}>
{availability}
</h6>
<h6 className="text-muted-foreground text-sm md:text-lg font-medium">
{data.address}
</h6>
{data.shelterSupplies.length > 0 && (
<>
<ShelterSupplyCategoryRow
title="Necessita voluntários:"
tags={tags.NeedVolunteers.map(getChipProps)}
/>
<ShelterSupplyCategoryRow
title="Necessita urgente doações de:"
tags={tags.NeedDonations.map(getChipProps)}
/>
<ShelterSupplyCategoryRow
title="Sobrando para doações:"
tags={tags.RemainingSupplies.map(getChipProps)}
/>
</>
)}
{data.updatedAt && (
<small className="text-sm md:text-md font-light text-muted-foreground mt-2">
Atualizado em {format(data.updatedAt, 'dd/MM/yyyy HH:mm')}
</small>
)}
</div>
<h6 className={cn('font-semibold text-md', availabilityClassName)}>
{availability}
</h6>
<h6 className="text-muted-foreground text-sm md:text-lg font-medium">
{data.address}
</h6>
{data.shelterSupplies.length > 0 && (
<>
<ShelterSupplyCategoryRow
title="Necessita volunários:"
tags={tags.NeedVolunteers.map(getChipProps)}
/>
<ShelterSupplyCategoryRow
title="Necessita urgente doações de:"
tags={tags.NeedDonations.map(getChipProps)}
/>
<ShelterSupplyCategoryRow
title="Sobrando para doações:"
tags={tags.RemainingSupplies.map(getChipProps)}
/>
</>
)}
{data.updatedAt && (
<small className="text-sm md:text-md font-light text-muted-foreground mt-2">
Atualizado em {format(data.updatedAt, 'dd/MM/yyyy HH:mm')}
</small>
)}
</div>
</Link>
);
};

Expand Down
9 changes: 3 additions & 6 deletions src/pages/Home/components/ShelterListView/ShelterListView.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { Fragment } from 'react';
import { CircleAlert, ListFilter, Loader } from 'lucide-react';
import { CircleAlert, ListFilter } from 'lucide-react';

import {
Alert,
Expand All @@ -11,6 +11,7 @@ import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
import { IShelterListViewProps } from './types';
import { useSearchParams } from 'react-router-dom';
import { LoadingSkeleton } from '@/components/LoadingSkeleton';

const ShelterListView = React.forwardRef<HTMLDivElement, IShelterListViewProps>(
(props, ref) => {
Expand All @@ -22,7 +23,6 @@ const ShelterListView = React.forwardRef<HTMLDivElement, IShelterListViewProps>(
hasMoreItems = false,
onSearchValueChange,
onFetchMoreData,
onSelectShelter,
className = '',
onOpenModal,
onClearSearch,
Expand Down Expand Up @@ -74,7 +74,7 @@ const ShelterListView = React.forwardRef<HTMLDivElement, IShelterListViewProps>(
</div>
<main ref={ref} className="flex flex-col gap-4" {...rest}>
{loading ? (
<Loader className="justify-self-center self-center w-5 h-5 animate-spin" />
<LoadingSkeleton amountItems={4}/>
) : data.length === 0 ? (
<NoFoundSearch />
) : (
Expand All @@ -83,9 +83,6 @@ const ShelterListView = React.forwardRef<HTMLDivElement, IShelterListViewProps>(
<ShelterListItem
key={idx}
data={s}
onClick={() =>
onSelectShelter ? onSelectShelter(s) : undefined
}
/>
))}
{hasMoreItems ? (
Expand Down

0 comments on commit 4e0d9c0

Please sign in to comment.