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';
|
||||
|
||||
import { CalendarIcon } from '@radix-ui/react-icons';
|
||||
import { LockClosedIcon } from '@radix-ui/react-icons';
|
||||
|
||||
import '../styles/locked-page.css';
|
||||
import LocationButton from '@/components/LockedContent';
|
||||
---
|
||||
|
||||
<Layout>
|
||||
|
@ -36,23 +36,10 @@ import '../styles/locked-page.css';
|
|||
|
||||
<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>
|
||||
<LocationButton client:load />
|
||||
</main>
|
||||
|
||||
<Button className="w-full">Paylaş</Button>
|
||||
</main>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
|
@ -63,9 +50,26 @@ import '../styles/locked-page.css';
|
|||
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();
|
||||
|
@ -98,17 +102,17 @@ import '../styles/locked-page.css';
|
|||
pos.lng,
|
||||
mapPos?.lat(),
|
||||
mapPos?.lng()
|
||||
);
|
||||
).toFixed(0);
|
||||
|
||||
locationInfo.textContent = `Aradaki Mesafe: ${totalDistanceInKM.toFixed(
|
||||
0
|
||||
)} km`;
|
||||
currentLocationMarkerView.position = pos;
|
||||
|
||||
locationInfo.textContent = `Aradaki Mesafe: ${totalDistanceInKM} km`;
|
||||
},
|
||||
() => {
|
||||
handleLocationError(true, infoWindow, map.getCenter()!);
|
||||
}
|
||||
),
|
||||
5000
|
||||
3000
|
||||
);
|
||||
|
||||
locationButton.addEventListener('click', () => {
|
||||
|
@ -121,10 +125,8 @@ import '../styles/locked-page.css';
|
|||
lng: position.coords.longitude,
|
||||
};
|
||||
|
||||
// infoWindow.setPosition(pos);
|
||||
// infoWindow.setContent('Location found.');
|
||||
// infoWindow.open(map);
|
||||
map.setCenter(pos);
|
||||
map.setZoom(12);
|
||||
},
|
||||
() => {
|
||||
handleLocationError(true, infoWindow, map.getCenter()!);
|
||||
|
@ -153,29 +155,3 @@ import '../styles/locked-page.css';
|
|||
|
||||
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>
|
||||
|
|
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",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user