Skip to content

Commit

Permalink
Merge pull request #71 from emiliosheinz/dev
Browse files Browse the repository at this point in the history
chore: production release
  • Loading branch information
emiliosheinz authored Jun 8, 2024
2 parents 126abc9 + ac30839 commit 8d0bc46
Show file tree
Hide file tree
Showing 13 changed files with 252 additions and 67 deletions.
11 changes: 8 additions & 3 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import nextBundleAnalyzer from "@next/bundle-analyzer";

/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation
*/
await import("./src/env.js");

/** @type {import("next").NextConfig} */
const config = {};

export default config;
const withBundleAnalyzer = nextBundleAnalyzer({
enabled: process.env.ANALYZE === "true",
});

export default withBundleAnalyzer(config);
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"type": "module",
"scripts": {
"build": "next build",
"build:with-analyzer": "ANALYZE=true yarn build",
"db:push": "prisma db push",
"db:studio": "prisma studio",
"dev": "next dev",
Expand All @@ -17,6 +18,7 @@
"dependencies": {
"@auth/prisma-adapter": "^1.4.0",
"@hookform/resolvers": "^3.3.4",
"@next/bundle-analyzer": "^14.2.3",
"@prisma/client": "^5.14.0",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-checkbox": "^1.0.4",
Expand All @@ -28,6 +30,7 @@
"@radix-ui/react-slot": "^1.0.2",
"@t3-oss/env-nextjs": "^0.10.1",
"@tanstack/react-query": "^5.25.0",
"@tanstack/react-query-devtools": "^5.40.1",
"@tanstack/react-table": "^8.17.3",
"@trpc/client": "next",
"@trpc/react-query": "next",
Expand Down
File renamed without changes.
18 changes: 16 additions & 2 deletions src/app/about/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { type Metadata } from "next";
import Image from "next/image";

export const metadata: Metadata = {
title: "Sobre",
description:
"O SOS Pet é um sistema dedicado a conectar animais resgatados de enchentes com abrigos temporários disponíveis. Acreditamos que, em momentos de crise, cada vida é importante, e é nossa missão ajudar a garantir que animais em situação de risco encontrem um local seguro e acolhedor enquanto aguardam seu retorno ao lar ou um novo começo.",
keywords: "Sobre, SOS Pet, animais, abrigos",
};

export const dynamic = "force-static";
export const revalidate = 60 * 60 * 24; // Revalidate almost once a day

export default function About() {
return (
<main className="mb-8">
Expand Down Expand Up @@ -61,8 +72,11 @@ export default function About() {
transformar um momento de crise em uma oportunidade para fazer a
diferença na vida de um animal. Juntos, podemos salvar vidas e
construir um futuro mais seguro para nossos amigos de quatro patas.
Além disso, esse projeto tem o código fonte aberto e disponível para colaboração:
<a href="https://github.com/emiliosheinz/sos-pet" target="blank"> https://github.com/emiliosheinz/sos-pet</a>
Além disso, esse projeto tem o código fonte aberto e disponível para
colaboração:
<a href="https://github.com/emiliosheinz/sos-pet" target="blank">
https://github.com/emiliosheinz/sos-pet
</a>
</p>
</div>
</div>
Expand Down
6 changes: 4 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import "~/styles/globals.css";
import { Inter } from "next/font/google";
import { TRPCReactProvider } from "~/trpc/react";
import { Analytics } from "@vercel/analytics/react";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";

import Providers from "./providers";
import Providers from "./_components/providers";
import { getServerAuthSession } from "~/server/auth";
import { Toaster } from "~/components/ui/sonner";
import { Footer } from "~/components/footer";
Expand Down Expand Up @@ -70,14 +71,15 @@ export default async function RootLayout({
const session = await getServerAuthSession();

return (
<html lang="en">
<html lang="pt-BR">
<body className={`font-sans ${inter.variable}`}>
<Providers session={session}>
<TRPCReactProvider>
<Header />
<div className="min-h-[60vh]">{children}</div>
<Lead />
<Footer />
<ReactQueryDevtools />
</TRPCReactProvider>
</Providers>
<Toaster />
Expand Down
22 changes: 9 additions & 13 deletions src/app/map/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@
import { type LatLngTuple } from "leaflet";
import { Loader2 } from "lucide-react";
import dynamic from "next/dynamic";
import { useEffect, useState } from "react";
import { Suspense, useEffect, useState } from "react";
import { Skeleton } from "~/components/ui/skeleton";
import { api } from "~/trpc/react";

const DEFAULT_LOCATION: LatLngTuple = [-30.0346, -51.2177]; // Porto Alegre

const Loader = <Skeleton className="h-[75vh] w-full max-w-7xl rounded-md" />;
const MapComponent = dynamic(() => import("~/components/map/"), {
loading: () => <Loader2 className="size-8 animate-spin" />,
ssr: false,
loading: () => Loader,
});

export default function Map() {
const { data, isLoading } = api.shelter.findAll.useQuery();
const [shelters] = api.shelter.findAll.useSuspenseQuery();
const [userLocation, setUserLocation] =
useState<LatLngTuple>(DEFAULT_LOCATION);

Expand All @@ -29,17 +31,11 @@ export default function Map() {
);
}, []);

if (isLoading && !data) {
return (
<div className="flex w-full justify-center pt-28">
<Loader2 className="size-8 animate-spin" />
</div>
);
}

return (
<main className="flex w-full justify-center pt-8">
<MapComponent userLocation={userLocation} shelter={data ?? []} />
<main className="relative flex w-full justify-center px-2 pt-8">
<Suspense fallback={Loader}>
<MapComponent userLocation={userLocation} shelter={shelters} />
</Suspense>
</main>
);
}
18 changes: 18 additions & 0 deletions src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const dynamic = "force-static";
export const revalidate = 60 * 60 * 24; // Revalidate almost once a day

export default function NotFound() {
return (
<main className="container mb-8 max-w-5xl pt-16">
<div className="flex h-[300px] flex-col justify-center">
<h1 className="mb-4 text-3xl font-bold">Página não encontrada</h1>
<div>
<p>
Ops! Algo saiu errado, a página que você procura possivelmente não
existe ou não foi encontrada.
</p>
</div>
</div>
</main>
);
}
68 changes: 41 additions & 27 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
"use client";
import { Card } from "~/components/card/";
import { SearchInput } from "~/components/search-input";
import { api } from "~/trpc/react";
import Fuse from "fuse.js";
import { useMemo } from "react";
import { type PropsWithChildren, Suspense, useMemo } from "react";
import { Skeleton } from "~/components/ui/skeleton";
import { useDebouncedState } from "~/hooks/use-debouced-state";
import { Alert, AlertDescription, AlertTitle } from "~/components/ui/alert";
import { FiInfo } from "react-icons/fi";
import dynamic from "next/dynamic";

const ShelterCard = dynamic(
() =>
import("~/components/shelter-card").then((module) => module.ShelterCard),
{ loading: () => <Skeleton className="h-[306px] w-full rounded-xl" /> },
);

const Grid = ({ children }: PropsWithChildren) => (
<div className="grid w-full max-w-7xl grid-cols-1 gap-5 md:grid-cols-2">
{children}
</div>
);

export default function Home() {
const { data, isLoading } = api.shelter.findAll.useQuery();
const [shelters] = api.shelter.findAll.useSuspenseQuery();
const [searchTerm, setSearchTerm] = useDebouncedState("", 300);

const filteredShelters = useMemo(() => {
const trimmedSearchTerm = searchTerm.trim();
if (trimmedSearchTerm.length === 0 || !data) {
return data ?? [];
if (trimmedSearchTerm.length === 0 || !shelters) {
return shelters ?? [];
}

const fuse = new Fuse(data, {
const fuse = new Fuse(shelters, {
keys: [
"name",
"addressStreet",
Expand All @@ -33,7 +45,7 @@ export default function Home() {
});

return fuse.search(trimmedSearchTerm).map((result) => result.item);
}, [data, searchTerm]);
}, [shelters, searchTerm]);

const handleSearch = (event: { target: { value: string } }) => {
setSearchTerm(event.target.value);
Expand All @@ -50,35 +62,37 @@ export default function Home() {
abrigo.
</AlertDescription>
</Alert>

<div className="mb-6 flex w-full max-w-7xl items-center justify-between space-x-4">
<SearchInput handleSearch={handleSearch} />
</div>
{!isLoading && !filteredShelters?.length && (
<div className="text-center text-gray-600">
<span className="mb-2 font-bold">
Desculpe, nenhum resultado encontrado.
</span>
<p>
Não encontramos nenhum resultado correspondente à sua busca. Por
favor, revise os critérios de pesquisa e tente novamente.
</p>
</div>
)}
<div className="grid w-full max-w-7xl grid-cols-1 gap-5 md:grid-cols-2">
{isLoading ? (
<>
<Suspense
fallback={
<Grid>
<Skeleton className="h-[306px] w-full rounded-xl" />
<Skeleton className="h-[306px] w-full rounded-xl" />
<Skeleton className="h-[306px] w-full rounded-xl" />
<Skeleton className="h-[306px] w-full rounded-xl" />
</>
</Grid>
}
>
{!!filteredShelters?.length ? (
<Grid>
{filteredShelters?.map((shelter) => (
<ShelterCard key={shelter.id} shelter={shelter} />
))}
</Grid>
) : (
filteredShelters?.map((shelter) => (
<Card key={shelter.id} shelter={shelter} />
))
<div className="max-w-md pt-5 text-center text-gray-600">
<span className="mb-2 font-bold">
Desculpe, nenhum resultado encontrado.
</span>
<p>
Não encontramos nenhum resultado correspondente à sua busca. Por
favor, revise os critérios de pesquisa e tente novamente.
</p>
</div>
)}
</div>
</Suspense>
</main>
);
}
14 changes: 12 additions & 2 deletions src/app/privacy-policy/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
export default function TermsOfUse() {
import { type Metadata } from "next";

export const metadata: Metadata = {
title: "Políticas de Privacidade",
description: "Políticas de privacidade do SOS Pet",
keywords: "políticas de privacidade, SOS Pet, animais, abrigos",
};

export const dynamic = "force-static";
export const revalidate = 60 * 60 * 24; // Revalidate almost once a day

export default function PrivacyPolicy() {
return (
<main className="container mb-8 max-w-5xl pt-16">
<h1 className="mb-10 text-3xl font-bold">Políticas de privacidade</h1>

<span className="mb-6 block font-light text-zinc-700">
Data de Atualização: 11 de maio de 2024
</span>

<div className="space-y-3 text-base font-light leading-7">
<p>
Esta Política de Privacidade explica como coletamos, usamos,
Expand Down
10 changes: 10 additions & 0 deletions src/app/terms-of-use/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { type Metadata } from "next";
import Link from "next/link";

export const metadata: Metadata = {
title: "Termos de Uso",
description: "Termos de Uso do SOS Pet",
keywords: "Termos de Uso, SOS Pet, animais, abrigos",
};

export const dynamic = "force-static";
export const revalidate = 60 * 60 * 24; // Revalidate almost once a day

export default function TermsOfUse() {
return (
<main className="container mb-8 max-w-5xl pt-16">
Expand Down
22 changes: 14 additions & 8 deletions src/components/map/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { useEffect } from "react";
import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
import "leaflet-defaulticon-compatibility";
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";

import { useEffect } from "react";
import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet";
import { type LatLngTuple } from "leaflet";
import { type Shelter } from "@prisma/client";
import { Card } from "../card";
import { ShelterCard } from "../shelter-card";

function UserLocationMap({ userLocation }: { userLocation: LatLngTuple }) {
const map = useMap();

useEffect(() => {
if (userLocation) {
map.setView(userLocation, 13);
map.setView(userLocation, 8);
}
}, [userLocation, map]);

Expand All @@ -28,9 +29,14 @@ export default function Map({
}) {
return (
<MapContainer
style={{ height: "800px", width: "100%", maxWidth: "1280px" }}
style={{
height: "75vh",
width: "100%",
maxWidth: "1280px",
borderRadius: "6px",
}}
center={userLocation}
zoom={13}
zoom={8}
>
<UserLocationMap userLocation={userLocation} />
<TileLayer
Expand All @@ -46,7 +52,7 @@ export default function Map({
position={[shelter.latitude, shelter.longitude]}
>
<Popup minWidth={390}>
<Card
<ShelterCard
shelter={shelter}
className="border-none p-2 text-black shadow-none"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Props = {
shelter: Shelter;
} & React.ComponentProps<typeof CardBase>;

export function Card({ shelter, ...otherProps }: Props) {
export function ShelterCard({ shelter, ...otherProps }: Props) {
const fullAddress = `${shelter.addressStreet} ${shelter.addressNumber} ${shelter.addressNeighborhood}, ${shelter.addressCity}, ${shelter.addressState}`;

const availableVacancies = shelter.capacity - shelter.occupancy;
Expand Down
Loading

0 comments on commit 8d0bc46

Please sign in to comment.