chore: change endpoint

This commit is contained in:
log101 2024-07-05 18:01:22 +03:00
parent 4f2cdaa302
commit 296083577a
9 changed files with 89 additions and 267 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -1,136 +1,146 @@
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { LockClosedIcon, LockOpen1Icon } from "@radix-ui/react-icons"
import { useEffect, useState } from "react"
import { LockClosedIcon, LockOpen1Icon } from "@radix-ui/react-icons";
import { useEffect, useState } from "react";
import "../styles/locked-content.css"
import type { Generated } from "kysely"
import { onLocationError } from "@/lib/error"
import "../styles/locked-content.css";
import type { Generated } from "kysely";
import { onLocationError } from "@/lib/error";
const incrementCounter = async (id: string | Generated<string>) =>
await fetch(`${import.meta.env.PUBLIC_HOME_URL}/api/content/increment?id=${id}`)
await fetch(`http://localhost:3000/api/location/increment/${id}`, {
method: "PATCH",
});
const LocationButton = ({
contentId = "",
imageUrl = "#",
location = ""
location = "",
}: {
contentId?: string | Generated<string>
imageUrl?: string
location?: string
contentId?: string | Generated<string>;
imageUrl?: string;
location?: string;
}) => {
const [atTarget, setAtTarget] = useState(false)
const [contentVisible, setContentVisible] = useState(false)
const [hasPermission, setHasPermission] = useState(false)
const [watchId, setWatchId] = useState<number>()
const [distanceRemain, setDistanceRemain] = useState<string>("")
const [atTarget, setAtTarget] = useState(false);
const [contentVisible, setContentVisible] = useState(false);
const [hasPermission, setHasPermission] = useState(false);
const [watchId, setWatchId] = useState<number>();
const [distanceRemain, setDistanceRemain] = useState<string>("");
const targetCoordinates = JSON.parse(location).coordinates
const targetCoordinates = JSON.parse(location);
console.log("coor", targetCoordinates);
const targetPos = {
lat: targetCoordinates[0],
lng: targetCoordinates[1]
}
lng: targetCoordinates[1],
};
const startWatchingLocation = () => {
setHasPermission(true)
setHasPermission(true);
if (!watchId) {
const id = navigator.geolocation.watchPosition(
(position: GeolocationPosition) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude
}
lng: position.coords.longitude,
};
// @ts-expect-error 3rd party script
const targetLatLng = L.latLng(targetPos)
const targetLatLng = L.latLng(targetPos);
// @ts-expect-error 3rd party script
const currentLatLng = L.latLng(pos)
const currentLatLng = L.latLng(pos);
const betweenMeters = currentLatLng.distanceTo(targetLatLng)
const betweenMeters = currentLatLng.distanceTo(targetLatLng);
if (betweenMeters > 1000) {
setDistanceRemain(`${(betweenMeters / 1000).toFixed()} KM`)
setDistanceRemain(`${(betweenMeters / 1000).toFixed()} KM`);
} else if (betweenMeters > 50) {
setDistanceRemain(`${betweenMeters.toFixed(0)} M`)
setDistanceRemain(`${betweenMeters.toFixed(0)} M`);
} else {
setAtTarget(true)
setAtTarget(true);
}
},
err => onLocationError(err),
(err) => onLocationError(err),
{ enableHighAccuracy: true, timeout: 27000, maximumAge: 10000 }
)
);
setWatchId(id)
}
setWatchId(id);
}
};
const handleUnlock = async () => {
setContentVisible(true)
await incrementCounter(contentId)
}
setContentVisible(true);
await incrementCounter(contentId);
};
useEffect(() => {
navigator.permissions.query({ name: "geolocation" }).then(permissionStatus => {
navigator.permissions
.query({ name: "geolocation" })
.then((permissionStatus) => {
if (permissionStatus.state === "granted") {
setHasPermission(true)
startWatchingLocation()
setHasPermission(true);
startWatchingLocation();
}
})
}, [])
});
}, []);
if (contentVisible) {
return (
<div className='w-full h-[475px] p-4 flex justify-center'>
<div className="w-full h-[475px] p-4 flex justify-center">
<img src={imageUrl} />
</div>
)
);
} else {
return (
<div className='w-full h-[475px] overflow-hidden border border-zinc-200 shadow-sm p-4 rounded'>
<div className="w-full h-[475px] overflow-hidden border border-zinc-200 shadow-sm p-4 rounded">
{atTarget ? (
<div className='flex flex-col justify-center items-center image-wrapper'>
<img src={imageUrl} className='blur-2xl h-[450px]' />
<div className="flex flex-col justify-center items-center image-wrapper">
<img src={imageUrl} className="blur-2xl h-[450px]" />
<div className='flex flex-col justify-center gap-4 overlay'>
<div className="flex flex-col justify-center gap-4 overlay">
<Button
size='lg'
className='text-lg p-6 animate-pulse bg-indigo-600 hover:bg-indigo-700 hover:animate-none border-2 border-indigo-800'
onClick={handleUnlock}>
<LockOpen1Icon className='mr-2 h-4 w-4' />
size="lg"
className="text-lg p-6 animate-pulse bg-indigo-600 hover:bg-indigo-700 hover:animate-none border-2 border-indigo-800"
onClick={handleUnlock}
>
<LockOpen1Icon className="mr-2 h-4 w-4" />
İçeriğin Kilidi ıldı
</Button>
<Card className='p-2'>
<CardContent className='pb-0 text-center'>İçeriği görmek için butona bas!</CardContent>
<Card className="p-2">
<CardContent className="pb-0 text-center">
İçeriği görmek için butona bas!
</CardContent>
</Card>
</div>
</div>
) : (
<div className='flex flex-col justify-center items-center image-wrapper'>
<img src={imageUrl} className='blur-2xl h-[450px]' />
<div className='flex flex-col justify-center gap-4 overlay'>
<Button size='lg' className='text-md'>
<LockClosedIcon className='mr-2 h-4 w-4' /> İçerik Kilitli
<div className="flex flex-col justify-center items-center image-wrapper">
<img src={imageUrl} className="blur-2xl h-[450px]" />
<div className="flex flex-col justify-center gap-4 overlay">
<Button size="lg" className="text-md">
<LockClosedIcon className="mr-2 h-4 w-4" /> İçerik Kilitli
</Button>
<Card className='p-2'>
<Card className="p-2">
{hasPermission ? (
<CardContent className='pb-0 text-center'>
<CardContent className="pb-0 text-center">
<p>İçeriği görmek için konuma gitmelisin!</p>
<p>{distanceRemain && `Kalan mesafe: ${distanceRemain}`}</p>
</CardContent>
) : (
<div className='flex flex-col gap-2'>
<CardContent className='pb-0 text-center'>
<div className="flex flex-col gap-2">
<CardContent className="pb-0 text-center">
Ne kadar yaklaştığını görmek için aşağıdaki butona bas.
</CardContent>
<Button
size='sm'
className='bg-green-700 hover:bg-green-600 text-md'
onClick={() => startWatchingLocation()}>
size="sm"
className="bg-green-700 hover:bg-green-600 text-md"
onClick={() => startWatchingLocation()}
>
Konum İzni Ver
</Button>
</div>
@ -140,8 +150,8 @@ const LocationButton = ({
</div>
)}
</div>
)
);
}
}
};
export default LocationButton
export default LocationButton;

1
src/env.d.ts vendored
View File

@ -1,3 +1,4 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />
/// <reference types="@types/google.maps" />
/// <reference types="@types/leaflet" />

View File

@ -19,16 +19,18 @@ import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import utc from 'dayjs/plugin/utc';
type Content = Omit<ContentTable, 'url'>;
type Content = ContentTable;
const { id } = Astro.params;
const res = await fetch(
`${import.meta.env.PUBLIC_HOME_URL}/api/content?id=${id}`
`http://localhost:3000/api/location/${id}`
);
const data: Content | null = res.status === 200 ? await res.json() : null;
console.log(data)
dayjs.extend(relativeTime);
dayjs.extend(utc);
@ -68,8 +70,8 @@ const dateFromNow = dayjs.utc(data?.created_at).from(dayjs.utc());
</Card>
<LockedContent
contentId={data?.id}
imageUrl={data?.blob_url}
contentId={data?.url}
imageUrl={`http://localhost:3000/images/${data?.blob_url}`}
location={data?.loc}
client:load
/>

View File

@ -1,39 +0,0 @@
import type { Database } from "@/lib/db"
import { createKysely } from "@vercel/postgres-kysely"
import type { APIRoute } from "astro"
export const GET: APIRoute = async ({ request }) => {
const contentId = new URL(request.url).searchParams.get("id")
if (!contentId) {
return new Response(null, {
status: 400,
statusText: "Content id is required"
})
}
const db = createKysely<Database>({ connectionString: import.meta.env.POSTGRES_URL })
try {
const result = await db
.updateTable("contents")
.set(eb => ({ unlocked_counter: eb("unlocked_counter", "+", 1) }))
.where("id", "=", contentId)
.executeTakeFirst()
if (result) {
return new Response(JSON.stringify({ counter: Number(result) }))
} else {
return new Response(null, {
status: 404,
statusText: "Could not increment the counter"
})
}
} catch (error) {
console.error("Error fetching content:", error)
return new Response(null, {
status: 500,
statusText: "Error while fetching content"
})
}
}

View File

@ -1,141 +0,0 @@
import { createClient } from "@supabase/supabase-js"
import type { APIRoute } from "astro"
import { createKysely } from "@vercel/postgres-kysely"
import { customAlphabet } from "nanoid"
import sharpService from "astro/assets/services/sharp"
import type { Database } from "@/lib/db"
export const POST: APIRoute = async ({ request }) => {
const formData = await request.formData()
const image = formData.get("selected-photo") as File
const author = formData.get("author")
const description = formData.get("description")
const geolocation = formData.get("geolocation")
if (!image || !geolocation) {
return new Response(null, {
status: 400,
statusText: "Image and geolocation are required fields"
})
}
const pos = geolocation.toString().split(",")
if (pos.length !== 2) {
return new Response(null, {
status: 400,
statusText: "Geolocation not correctly formatted"
})
}
const supabaseUrl = import.meta.env.SUPABASE_URL
const supabaseKey = import.meta.env.SUPABASE_KEY
const supabase = createClient(supabaseUrl, supabaseKey)
const nanoid = customAlphabet("abcdefghijklmnoprstuvyz", 10)
const randomImageId = nanoid()
const imageName = `${image.name.replace(/\.[^/.]+$/, "")}${randomImageId}.webp`
const imageBuf = await image.arrayBuffer()
const { data, format } = await sharpService.transform(
new Uint8Array(imageBuf),
{ src: imageName, format: "webp" },
{ domains: [], remotePatterns: [], service: { entrypoint: "", config: { limitInputPixels: false } } }
)
console.log(format)
const { error } = await supabase.storage.from("images").upload(`public/${imageName}`, data, {
cacheControl: "3600",
upsert: false,
contentType: "image/webp"
})
if (error) {
console.error(error.message, imageName, error.cause)
return new Response(null, {
status: 400,
statusText: error.message
})
}
const imagePublicUrl = `https://sozfqjbdyppxfwhqktja.supabase.co/storage/v1/object/public/images/public/${imageName}`
const db = createKysely<Database>({ connectionString: import.meta.env.POSTGRES_URL })
const newUrl = nanoid()
const res = await db
.insertInto("contents")
.values({
url: `${newUrl.slice(0, 3)}-${newUrl.slice(3, 7)}-${newUrl.slice(7)}`,
blob_url: imagePublicUrl,
author: author?.toString() ?? "",
description: description?.toString() ?? "",
loc: `SRID=4326;POINT(${pos[0]} ${pos[1]})`
})
.returning("url")
.executeTakeFirst()
if (res?.url) {
return new Response(
JSON.stringify({
url: res.url
})
)
} else {
return new Response(null, {
status: 500,
statusText: "Error while saving data"
})
}
}
export const GET: APIRoute = async ({ request }) => {
const contentId = new URL(request.url).searchParams.get("id")
if (!contentId) {
return new Response(null, {
status: 400,
statusText: "Content id is required"
})
}
const db = createKysely<Database>({ connectionString: import.meta.env.POSTGRES_URL })
try {
const content = await db
.selectFrom("contents")
.select(({ fn }) => [
"id",
"blob_url",
fn<string>("ST_AsGeoJSON", ["loc"]).as("loc"),
"description",
"author",
"created_at",
"unlocked_counter"
])
.where("url", "=", contentId)
.executeTakeFirst()
if (content) {
return new Response(JSON.stringify(content))
} else {
return new Response(null, {
status: 404,
statusText: "Content not found"
})
}
} catch (error) {
console.error("Error fetching content:", error)
return new Response(null, {
status: 500,
statusText: "Error while fetching content"
})
}
}

View File

@ -1,11 +0,0 @@
import type { APIRoute } from "astro"
export const POST: APIRoute = async ({ request }) => {
const data = await request.json()
console.log(data)
return new Response(null, {
status: 200
})
}

View File

@ -195,7 +195,7 @@ import { Label } from '@/components/ui/label';
const formData = new FormData(e.target as HTMLFormElement);
const res = await fetch(`/api/content`, {
const res = await fetch(`http://127.0.0.1:3000/api/location`, {
method: 'POST',
body: formData,
});

View File

@ -1,6 +1,6 @@
const data = JSON.parse(document.getElementById('map').dataset.targetLocation)
const TARGET_LOCATION = data.coordinates
const TARGET_LOCATION = data
function startWatchingLocation() {
map.locate({ watch: true })