diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..1c2aa65 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": "next/core-web-vitals" + "extends": "next/core-web-vitals" } diff --git a/package-lock.json b/package-lock.json index 736c4a0..8f7e39b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@types/node": "20.4.9", "@types/react": "18.2.20", "@types/react-dom": "18.2.7", + "@uidotdev/usehooks": "^2.4.1", "airtable": "^0.12.1", "autoprefixer": "10.4.14", "encoding": "^0.1.13", @@ -674,6 +675,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@uidotdev/usehooks": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.4.1.tgz", + "integrity": "sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg==", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", diff --git a/package.json b/package.json index b26438f..fb6c7a2 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@types/node": "20.4.9", "@types/react": "18.2.20", "@types/react-dom": "18.2.7", + "@uidotdev/usehooks": "^2.4.1", "airtable": "^0.12.1", "autoprefixer": "10.4.14", "encoding": "^0.1.13", diff --git a/src/app/(surfspots)/favorite/page.tsx b/src/app/(surfspots)/favorite/page.tsx index 9d7a937..aeaa716 100644 --- a/src/app/(surfspots)/favorite/page.tsx +++ b/src/app/(surfspots)/favorite/page.tsx @@ -1,7 +1,5 @@ import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"; import { cookies } from "next/headers"; -import { fetchSpotSurfData } from "@/app/utils/surfUtils"; -import { FullSpot, SurfSpot, FavoriteSpot } from "@/app/constants/types"; import Link from "next/link"; //Components diff --git a/src/app/(surfspots)/layout.tsx b/src/app/(surfspots)/layout.tsx index 387e723..f5c0950 100644 --- a/src/app/(surfspots)/layout.tsx +++ b/src/app/(surfspots)/layout.tsx @@ -3,6 +3,7 @@ import { redirect } from "next/navigation"; import { cookies } from "next/headers"; import type { Database } from "../lib/database.types"; import Link from "next/link"; +import SearchPintxos from "../components/atom/SearchPintxos"; //utils import { getTidesData, getCurrentTide } from "../utils/surfUtils"; @@ -27,31 +28,36 @@ export default async function FavoriteSpotsLayout({ return (
-
- {user && ( - +
+
+ {user && ( + +
+ Favorite +
+ + )} +
- Favorite + All Pintxos
- )} - -
- All Pintxos -
- +
+
+ + +
-
{children}
diff --git a/src/app/(surfspots)/spots/SpotsList.tsx b/src/app/(surfspots)/spots/SpotsList.tsx index 61dd730..27e100e 100644 --- a/src/app/(surfspots)/spots/SpotsList.tsx +++ b/src/app/(surfspots)/spots/SpotsList.tsx @@ -19,7 +19,7 @@ export default async function SpotsList() { return ( <> -
+
{allSpotsData && allSpotsData.map((spot) => { if (spot) { diff --git a/src/app/components/atom/SearchPintxos.tsx b/src/app/components/atom/SearchPintxos.tsx new file mode 100644 index 0000000..cf949b6 --- /dev/null +++ b/src/app/components/atom/SearchPintxos.tsx @@ -0,0 +1,84 @@ +"use client"; +import { useState, useEffect } from "react"; +import { createClientComponentClient } from "@supabase/auth-helpers-nextjs"; +import type { Database } from "@/app/lib/database.types"; +import Link from "next/link"; +import { useClickAway } from "@uidotdev/usehooks"; + +type SpotConditions = Database["public"]["Tables"]["spot_conditions"]["Row"]; + +const SearchPintxos = () => { + const [pintxos, setPintxos] = useState(null); + const [search, setSearch] = useState(""); + const supabase = createClientComponentClient(); + const ref = useClickAway(() => { + setPintxos(null); + setSearch(""); + }); + + useEffect(() => { + async function searchPintxos() { + if (search.trim() === "") { + setPintxos(null); + return; + } + const { data, error } = await supabase + .from("spot_conditions") + .select("*") + .like("name", `%${search}%`); + + if (error) { + console.log("ERROR", error.message); + } + setPintxos(data); + } + searchPintxos(); + }, [search]); + + const handlePintxoClick = (): void => { + setPintxos(null); + setSearch(""); + }; + + console.log("SEARCH", search); + console.log("PINTXO", pintxos); + + return ( +
+
} + > + setSearch(e.target.value)} + className="border border-secondary/50 rounded-md p-2 !bg-transparent font-body text-md font-light text-secondary ring-0 focus:ring-secondary focus:outline-none" + /> + {pintxos && pintxos.length > 0 && ( +
+ {pintxos?.map((pintxo) => ( +
handlePintxoClick()} + className="w-full" + > + +
+ {pintxo.name} +
+ +
+ ))} +
+ )} +
+
+ ); +}; + +export default SearchPintxos; diff --git a/src/app/utils/surfUtils.ts b/src/app/utils/surfUtils.ts index 50065f5..694ee74 100644 --- a/src/app/utils/surfUtils.ts +++ b/src/app/utils/surfUtils.ts @@ -3,16 +3,7 @@ import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"; import { cookies } from "next/headers"; import { DateTime } from "luxon"; //types -import { - FullSpot, - SurfSpot, - HourlySurfData, - FavoriteSpot, - TideType, - HourlyWeatherData, - ForecastDataResponse, - Pintxo, -} from "../constants/types"; +import { TideType, Pintxo } from "../constants/types"; import { Database } from "../lib/database.types"; type PintxoConditions = Database["public"]["Tables"]["spot_conditions"]["Row"]; type WeekdayPintxoCondition = { @@ -58,30 +49,6 @@ function getAverageDirection(direction: string): number { return avgDirection; } -export async function fetchSpotSurfData(spot: SurfSpot) { - const marineApiUrl = `https://marine-api.open-meteo.com/v1/marine?latitude=${spot.lat}&longitude=${spot.long}&hourly=wave_height,wave_direction,wave_period,swell_wave_height,swell_wave_direction,swell_wave_period`; - const forecastApiUrl = `https://api.open-meteo.com/v1/forecast?latitude=${spot.lat}&longitude=${spot.long}&hourly=temperature_2m,precipitation,visibility,windspeed_10m,winddirection_10m,temperature_80m,uv_index&models=best_match`; - - const [marineResponse, forecastResponse] = await Promise.all([ - fetch(marineApiUrl), - fetch(forecastApiUrl), - ]); - - if (!marineResponse.ok) { - throw new Error(`Failed to fetch data for spot ${spot.name}`); - } - - const hourlySurfData: HourlySurfData = await marineResponse.json(); - const forecastData: ForecastDataResponse = await forecastResponse.json(); - const hourlyWeatherData: HourlyWeatherData = forecastData.hourly; - - return { - ...spot, - hourlySpotForecast: hourlySurfData, - hourlyWeatherData: hourlyWeatherData, - }; -} - export function getCurrentWaveHeightForSpot( spot: PintxoConditions ): string | null { diff --git a/src/app/utils/uiUtils.ts b/src/app/utils/uiUtils.ts index 278dd8b..91fdcf5 100644 --- a/src/app/utils/uiUtils.ts +++ b/src/app/utils/uiUtils.ts @@ -1,7 +1,6 @@ export function getPintxoColor(condition: string): string { switch (condition) { case "Empty Plate": - console.log("condition", condition); return "bg-purple-400"; case "Bread Only": return "bg-red-400"; diff --git a/tsconfig.json b/tsconfig.json index eb0b41d..cdd8998 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,28 +1,29 @@ { - "compilerOptions": { - "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] - } - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "noUnusedLocals": false, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] } diff --git a/yarn.lock b/yarn.lock index 3379c73..2e33e84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -375,6 +375,11 @@ "@typescript-eslint/types" "6.3.0" eslint-visitor-keys "^3.4.1" +"@uidotdev/usehooks@^2.4.1": + version "2.4.1" + resolved "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.4.1.tgz" + integrity sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" @@ -2274,7 +2279,7 @@ queue-microtask@^1.2.2: resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -"react-dom@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0", react-dom@^18.2.0, react-dom@>=15.0.0, react-dom@18.2.0: +"react-dom@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0", react-dom@^18.2.0, react-dom@>=15.0.0, react-dom@>=18.0.0, react-dom@18.2.0: version "18.2.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== @@ -2317,7 +2322,7 @@ react-transition-group@2.9.0: prop-types "^15.6.2" react-lifecycles-compat "^3.0.4" -"react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0", react@^18.2.0, "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=15.0.0, react@18.2.0: +"react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0", react@^18.2.0, "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=15.0.0, react@>=18.0.0, react@18.2.0: version "18.2.0" resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==