feat: unlock content based on location

This commit is contained in:
log101 2024-01-16 17:57:13 +03:00
parent c058591464
commit 5de3797797
7 changed files with 348 additions and 54 deletions

18
prettierrc.json Normal file
View File

@ -0,0 +1,18 @@
{
"endOfLine": "lf",
"printWidth": 120,
"arrowParens": "avoid",
"bracketSpacing": true,
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"bracketSameLine": false,
"jsxSingleQuote": true,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"requirePragma": false,
"semi": false,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false
}

BIN
public/blue-dot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,81 @@
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import distance from "@/utils/distance";
import { LockClosedIcon, LockOpen1Icon } from "@radix-ui/react-icons";
import { useEffect, useState } from "react";
import "../styles/locked-content.css";
const LocationButton = () => {
const [isLocked, setIsLocked] = useState(true);
useEffect(() => {
setInterval(
() =>
navigator.geolocation.getCurrentPosition(
(position: GeolocationPosition) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
const totalDistanceInKM = distance(
pos.lat,
pos.lng,
pos.lat,
pos.lng
).toFixed(0);
if (totalDistanceInKM === "0") {
setIsLocked(false);
}
}
),
3000
);
}, []);
if (isLocked) {
return (
<div className="module w-full h-[450px] p-4">
<div className="module-inside flex flex-col justify-center items-center gap-2">
<div>
<Button size={"lg"}>
<LockClosedIcon className="mr-2 h-4 w-4" /> İçerik Kilitli
</Button>
</div>
<Card className="p-2">
<CardContent className="pb-0 text-center">
İçeriği görmek için konuma gitmelisin!
</CardContent>
</Card>
</div>
</div>
);
} else {
return (
<div className="module w-full h-[450px] p-4">
<div className="module-inside flex flex-col justify-center items-center gap-2">
<div>
<Button size={"lg"} asChild>
<a href="/unlocked">
<LockOpen1Icon className="mr-2 h-4 w-4" />
İçeriğin Kilidi ıldı
</a>
</Button>
</div>
<Card className="p-2">
<CardContent className="pb-0 text-center">
İçeriği görmek için butona bas!
</CardContent>
</Card>
</div>
</div>
);
}
};
export default LocationButton;

View File

@ -11,9 +11,9 @@ import {
} from '@/components/ui/card'; } from '@/components/ui/card';
import { CalendarIcon } from '@radix-ui/react-icons'; import { CalendarIcon } from '@radix-ui/react-icons';
import { LockClosedIcon } from '@radix-ui/react-icons';
import '../styles/locked-page.css'; import '../styles/locked-page.css';
import LocationButton from '@/components/LockedContent';
--- ---
<Layout> <Layout>
@ -36,23 +36,10 @@ import '../styles/locked-page.css';
<div id="map" class="w-full h-[450px]"></div> <div id="map" class="w-full h-[450px]"></div>
<div class="module w-full h-[450px] p-4"> <LocationButton client:load />
<div
class="module-inside flex flex-col justify-center items-center gap-2"
>
<Button>
<LockClosedIcon className="mr-2 h-4 w-4" />İçerik Kilitli
</Button>
<Card className="p-2">
<CardContent className="pb-0 text-center">
İçeriği görmek için konuma gitmelisin!
</CardContent>
</Card>
</div>
</div>
<Button className="w-full">Paylaş</Button>
</main> </main>
<Button className="w-full">Paylaş</Button>
</Layout> </Layout>
<script> <script>
@ -63,9 +50,26 @@ import '../styles/locked-page.css';
const { Map } = (await google.maps.importLibrary( const { Map } = (await google.maps.importLibrary(
'maps' 'maps'
)) as google.maps.MapsLibrary; )) as google.maps.MapsLibrary;
const { AdvancedMarkerElement } = (await google.maps.importLibrary(
'marker'
)) as google.maps.MarkerLibrary;
map = new Map(document.getElementById('map') as HTMLElement, { map = new Map(document.getElementById('map') as HTMLElement, {
center: { lat: -34.397, lng: 150.644 }, center: { lat: -34.397, lng: 150.644 },
zoom: 8, zoom: 8,
mapId: 'DEMO_MAP_ID',
mapTypeControl: false,
});
const currentLocationIcon = document.createElement('img');
currentLocationIcon.src = '/blue-dot.png';
const currentLocationMarkerView = new AdvancedMarkerElement({
map,
position: { lat: 37.434, lng: -122.082 },
content: currentLocationIcon,
title: 'Current Location',
}); });
infoWindow = new google.maps.InfoWindow(); infoWindow = new google.maps.InfoWindow();
@ -98,17 +102,17 @@ import '../styles/locked-page.css';
pos.lng, pos.lng,
mapPos?.lat(), mapPos?.lat(),
mapPos?.lng() mapPos?.lng()
); ).toFixed(0);
locationInfo.textContent = `Aradaki Mesafe: ${totalDistanceInKM.toFixed( currentLocationMarkerView.position = pos;
0
)} km`; locationInfo.textContent = `Aradaki Mesafe: ${totalDistanceInKM} km`;
}, },
() => { () => {
handleLocationError(true, infoWindow, map.getCenter()!); handleLocationError(true, infoWindow, map.getCenter()!);
} }
), ),
5000 3000
); );
locationButton.addEventListener('click', () => { locationButton.addEventListener('click', () => {
@ -121,10 +125,8 @@ import '../styles/locked-page.css';
lng: position.coords.longitude, lng: position.coords.longitude,
}; };
// infoWindow.setPosition(pos);
// infoWindow.setContent('Location found.');
// infoWindow.open(map);
map.setCenter(pos); map.setCenter(pos);
map.setZoom(12);
}, },
() => { () => {
handleLocationError(true, infoWindow, map.getCenter()!); handleLocationError(true, infoWindow, map.getCenter()!);
@ -153,29 +155,3 @@ import '../styles/locked-page.css';
initMap(); initMap();
</script> </script>
<style>
.module {
display: grid;
place-items: center;
position: relative;
overflow: hidden;
}
.module::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;
filter: blur(20px);
}
.module-inside {
position: relative;
}
</style>

198
src/pages/unlocked.astro Normal file
View File

@ -0,0 +1,198 @@
---
import '@/styles/globals.css';
import Layout from '../layouts/Layout.astro';
import { Button } from '@/components/ui/button';
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { CalendarIcon } from '@radix-ui/react-icons';
import { LockClosedIcon } from '@radix-ui/react-icons';
import '../styles/locked-page.css';
---
<Layout>
<main class="flex flex-col gap-3 my-4 items-center">
<Card className="w-full">
<CardHeader>
<CardTitle>Ayşe</CardTitle>
</CardHeader>
<CardContent>
<p>
Senin için bir sürpriz hazırladım, ama önce aşağıdaki konuma gitmen
lazım 😘
</p>
</CardContent>
<CardFooter className="gap-2">
<CalendarIcon />
<p>5 saat önce</p>
</CardFooter>
</Card>
<div id="map" class="w-full h-[450px]"></div>
<div class="module w-full h-[450px] p-4">
<div
class="module-inside flex flex-col justify-center items-center gap-2"
>
<Button>
<LockClosedIcon className="mr-2 h-4 w-4" />İçerik Kilitli
</Button>
<Card className="p-2">
<CardContent className="pb-0 text-center">
İçeriği görmek için konuma gitmelisin!
</CardContent>
</Card>
</div>
</div>
<Button className="w-full">Paylaş</Button>
</main>
</Layout>
<script>
import distance from '../utils/distance';
let map: google.maps.Map, infoWindow: google.maps.InfoWindow;
async function initMap(): Promise<void> {
const { Map } = (await google.maps.importLibrary(
'maps'
)) as google.maps.MapsLibrary;
const { AdvancedMarkerElement } = (await google.maps.importLibrary(
'marker'
)) as google.maps.MarkerLibrary;
map = new Map(document.getElementById('map') as HTMLElement, {
center: { lat: -34.397, lng: 150.644 },
zoom: 8,
mapId: 'DEMO_MAP_ID',
mapTypeControl: false,
});
const currentLocationIcon = document.createElement('img');
currentLocationIcon.src = '/blue-dot.png';
const currentLocationMarkerView = new AdvancedMarkerElement({
map,
position: { lat: 37.434, lng: -122.082 },
content: currentLocationIcon,
title: 'Current Location',
});
infoWindow = new google.maps.InfoWindow();
const locationButton = document.createElement('button');
const locationInfo = document.createElement('button');
locationButton.textContent = 'Konumuma Git';
locationInfo.textContent = 'Mesafe hesaplanıyor...';
locationButton.classList.add('custom-map-control-button');
locationInfo.classList.add('custom-map-control-button');
map.controls[google.maps.ControlPosition.TOP_CENTER].push(locationButton);
map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(locationInfo);
setInterval(
() =>
navigator.geolocation.getCurrentPosition(
(position: GeolocationPosition) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
const mapPos = map.getCenter();
const totalDistanceInKM = distance(
pos.lat,
pos.lng,
mapPos?.lat(),
mapPos?.lng()
).toFixed(0);
if (totalDistanceInKM === '0') window.location.assign('/unlocked');
currentLocationMarkerView.position = pos;
locationInfo.textContent = `Aradaki Mesafe: ${totalDistanceInKM} km`;
},
() => {
handleLocationError(true, infoWindow, map.getCenter()!);
}
),
3000
);
locationButton.addEventListener('click', () => {
// Try HTML5 geolocation.
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position: GeolocationPosition) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
map.setCenter(pos);
map.setZoom(12);
},
() => {
handleLocationError(true, infoWindow, map.getCenter()!);
}
);
} else {
// Browser doesn't support Geolocation
handleLocationError(false, infoWindow, map.getCenter()!);
}
});
}
function handleLocationError(
browserHasGeolocation: boolean,
infoWindow: google.maps.InfoWindow,
pos: google.maps.LatLng
) {
infoWindow.setPosition(pos);
infoWindow.setContent(
browserHasGeolocation
? 'Error: Konumunuz tespit edilemedi.'
: 'Error: Tarayıcınız konum tespitini desteklemiyor.'
);
infoWindow.open(map);
}
initMap();
</script>
<style>
.module {
display: grid;
place-items: center;
position: relative;
overflow: hidden;
}
.module::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;
filter: blur(20px);
}
.module-inside {
position: relative;
}
</style>

View File

@ -0,0 +1,23 @@
.module {
display: grid;
place-items: center;
position: relative;
overflow: hidden;
}
.module::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;
filter: blur(20px);
}
.module-inside {
position: relative;
}

View File

@ -5,9 +5,7 @@
"jsxImportSource": "react", "jsxImportSource": "react",
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": [ "@/*": ["./src/*"]
"./src/*"
]
} }
} }
} }