feat: unlock content based on location
This commit is contained in:
parent
c058591464
commit
5de3797797
18
prettierrc.json
Normal file
18
prettierrc.json
Normal 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
BIN
public/blue-dot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
81
src/components/LockedContent.tsx
Normal file
81
src/components/LockedContent.tsx
Normal 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 Açı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;
|
|
@ -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
|
</main>
|
||||||
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>
|
<Button className="w-full">Paylaş</Button>
|
||||||
</main>
|
|
||||||
</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
198
src/pages/unlocked.astro
Normal 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>
|
23
src/styles/locked-content.css
Normal file
23
src/styles/locked-content.css
Normal 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;
|
||||||
|
}
|
|
@ -5,9 +5,7 @@
|
||||||
"jsxImportSource": "react",
|
"jsxImportSource": "react",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": ["./src/*"]
|
||||||
"./src/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user