feat: fetch location and content data from database

This commit is contained in:
log101 2024-01-26 20:32:32 +03:00
parent 38dd1eb2f1
commit 6e42f5d55e
10 changed files with 150 additions and 94 deletions

View File

@ -9,6 +9,6 @@ export default defineConfig({
integrations: [react(), tailwind({
applyBaseStyles: false
})],
output: "hybrid",
output: "server",
adapter: vercel()
});

28
package-lock.json generated
View File

@ -25,6 +25,7 @@
"clsx": "^2.1.0",
"kysely": "^0.26.0",
"lucide-react": "^0.309.0",
"nanoid": "^5.0.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwind-merge": "^2.2.0",
@ -5003,9 +5004,9 @@
}
},
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.4.tgz",
"integrity": "sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==",
"funding": [
{
"type": "github",
@ -5013,10 +5014,10 @@
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
"nanoid": "bin/nanoid.js"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
"node": "^18 || >=20"
}
},
"node_modules/napi-build-utils": {
@ -5689,6 +5690,23 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
"node_modules/postcss/node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/postgres-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",

View File

@ -27,6 +27,7 @@
"clsx": "^2.1.0",
"kysely": "^0.26.0",
"lucide-react": "^0.309.0",
"nanoid": "^5.0.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwind-merge": "^2.2.0",

View File

@ -7,7 +7,7 @@ import { useEffect, useState } from "react"
import "../styles/locked-content.css"
const LocationButton = () => {
const LocationButton = ({ imageUrl = "#" }: { imageUrl?: string }) => {
const [atTarget, setAtTarget] = useState(false)
const [contentVisible, setContentVisible] = useState(false)
const [hasPermission, setHasPermission] = useState(false)
@ -47,29 +47,36 @@ const LocationButton = () => {
}, [])
if (contentVisible) {
return <div className='module-unlocked w-full h-[450px] p-4'></div>
return (
<div className='w-full h-[475px] p-4 flex justify-center'>
<img src={imageUrl} />
</div>
)
} else {
return (
<div className='module w-full h-[450px] p-4'>
<div className='w-full h-[475px] p-4'>
{atTarget ? (
<div className='module-inside flex flex-col justify-center items-center gap-2'>
<div>
<div className='flex flex-col justify-center items-center image-wrapper'>
<img src={imageUrl} className='blur-lg h-[450px]' />
<div className='flex flex-col justify-center gap-2 overlay'>
<Button size={"lg"} onClick={() => setContentVisible(true)}>
<LockOpen1Icon className='mr-2 h-4 w-4' />
İçeriğin Kilidi ıldı
</Button>
</div>
<Card className='p-2'>
<CardContent className='pb-0 text-center'>İçeriği görmek için butona bas!</CardContent>
</Card>
</div>
</div>
) : (
<div className='module-inside flex flex-col justify-center items-center gap-4'>
<Button size={"lg"}>
<div className='flex flex-col justify-center items-center image-wrapper'>
<img src={imageUrl} className='blur-lg h-[450px]' />
<div className='flex flex-col justify-center gap-2 overlay'>
<Button size='lg'>
<LockClosedIcon className='mr-2 h-4 w-4' /> İçerik Kilitli
</Button>
<Card className='p-2'>
{hasPermission ? (
<CardContent className='pb-0 text-center'>İçeriği görmek için konuma gitmelisin!</CardContent>
@ -90,6 +97,7 @@ const LocationButton = () => {
)}
</Card>
</div>
</div>
)}
</div>
)

13
src/lib/db.ts Normal file
View File

@ -0,0 +1,13 @@
import type { Generated } from "kysely"
export interface Database {
contents: ContentTable
}
export interface ContentTable {
id: Generated<string>
url: string
blob_url: string
loc: string
description: string
}

View File

@ -15,6 +15,14 @@ import { CalendarIcon } from '@radix-ui/react-icons';
import '../styles/locked-page.css';
import LockedContent from '@/components/LockedContent';
import { Separator } from '@/components/ui/separator';
const { id } = Astro.params;
const res = await fetch(`http://localhost:4321/api/content?id=${id}`);
const data = await res.json();
console.log(data);
---
<Layout>
@ -39,10 +47,7 @@ import { Separator } from '@/components/ui/separator';
<CardTitle>Abdurrahman</CardTitle>
</CardHeader>
<CardContent>
<p>
Hacı sana çok özel bir sürpriz hazırladık, aşağıdaki konuma muhakak
git.
</p>
<p>{data.description}</p>
</CardContent>
<CardFooter className="gap-2">
<CalendarIcon />
@ -50,9 +55,14 @@ import { Separator } from '@/components/ui/separator';
</CardFooter>
</Card>
<LockedContent client:load />
<LockedContent imageUrl={data.blob_url} client:load />
<div id="map" class="w-full h-[450px] rounded"></div>
<div
id="map"
class="w-full h-[450px] rounded"
data-target-location={data.loc}
>
</div>
<Button className="w-full">Paylaş</Button>
<div class="flex justify-center">

View File

@ -1,20 +1,9 @@
export const prerender = false
import { put } from "@vercel/blob"
import type { Generated } from "kysely"
import type { APIRoute } from "astro"
import { createKysely } from "@vercel/postgres-kysely"
import { customAlphabet } from "nanoid"
interface ContentTable {
id: Generated<number>
blob_url: string
loc: string
description: string
}
interface Database {
contents: ContentTable
}
import type { Database } from "../../lib/db"
export const POST: APIRoute = async ({ request }) => {
const data = await request.formData()
@ -43,9 +32,14 @@ export const POST: APIRoute = async ({ request }) => {
const db = createKysely<Database>({ connectionString: import.meta.env.POSTGRES_URL })
const nanoid = customAlphabet("abcdefghijklmnoprstuvyz", 10)
const newUrl = nanoid()
const res = await db
.insertInto("contents")
.values({
url: `${newUrl.slice(0, 3)}-${newUrl.slice(3, 7)}-${newUrl.slice(7)}`,
blob_url: blob.url,
description: description?.toString() ?? "",
loc: `SRID=4326;POINT(${pos[0]} ${pos[1]})`
@ -66,3 +60,39 @@ export const POST: APIRoute = async ({ request }) => {
})
}
}
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 }) => ["blob_url", fn<string>("ST_AsGeoJSON", ["loc"]).as("loc"), "description"])
.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,4 +1,6 @@
---
export const prerender = true;
import '@/styles/globals.css';
import Layout from '../layouts/Layout.astro';
import { Button } from '@/components/ui/button';
@ -109,7 +111,7 @@ import { Textarea } from '@/components/ui/textarea';
const formData = new FormData(e.target as HTMLFormElement);
const response = await fetch(`/create-url`, {
const response = await fetch(`/api/content`, {
method: 'POST',
body: formData,
});

View File

@ -1,4 +1,6 @@
const TARGET_LOCATION = [41.01907795861253, 29.01715377829709];
const data = JSON.parse(document.getElementById('map').dataset.targetLocation)
const TARGET_LOCATION = data.coordinates
var map = L.map('map').setView(TARGET_LOCATION, 13);

View File

@ -1,42 +1,14 @@
.module {
display: grid;
place-items: center;
.image-wrapper {
position: relative;
overflow: hidden;
}
.module-unlocked {
display: grid;
place-items: center;
position: relative;
overflow: hidden;
}
.module::before {
content: "";
top: 0;
left: 0;
width: 100%;
height: 100%;
.overlay {
position: absolute;
background-image: url("/sample-selfie.webp");
background-position: center;
background-repeat: no-repeat;
filter: blur(20px);
}
.module-unlocked::before {
content: "";
top: 0;
left: 0;
width: 100%;
height: 100%;
position: absolute;
background-image: url("/sample-selfie.webp");
background-position: center;
background-repeat: no-repeat;
}
/* center overlay text */
display: flex;
align-items: center;
justify-content: center;
.module-inside {
position: relative;
inset: 0;
}