♻️ Restructure: Move Astro to repository root
BREAKING CHANGE: Astro project is now at repository root - Removed dealplustech-astro subdirectory - Moved all Astro files to root - Updated PostCSS config to .cjs - Removed old Next.js files ✅ 11 pages built successfully ✅ Cookie consent banner included ✅ Privacy/Terms links in footer ✅ Ready for Easypanel deployment (no root dir needed) Migration path: - Old structure: /dealplustech-astro/ - New structure: / (root)
This commit is contained in:
188
src/components/consent/ConsentPreferences.astro
Normal file
188
src/components/consent/ConsentPreferences.astro
Normal file
@@ -0,0 +1,188 @@
|
||||
---
|
||||
---
|
||||
|
||||
<div id="consent-preferences-modal" class="fixed inset-0 z-50 hidden">
|
||||
<div class="fixed inset-0 bg-black/50 transition-opacity" id="consent-modal-backdrop"></div>
|
||||
<div class="fixed inset-0 flex items-center justify-center p-4">
|
||||
<div class="relative bg-white rounded-xl shadow-2xl w-full max-w-lg max-h-[90vh] overflow-y-auto">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-semibold text-gray-900 mb-2">ตั้งค่าคุกกี้</h2>
|
||||
<p class="text-sm text-gray-600 mb-6">
|
||||
คุณสามารถปรับแต่งการตั้งค่าคุกกี้ได้ตามต้องการ
|
||||
</p>
|
||||
|
||||
<div class="space-y-5">
|
||||
<div class="flex items-center justify-between p-4 bg-gray-50 rounded-lg">
|
||||
<div>
|
||||
<span class="font-medium text-gray-900">จำเป็น (เปิดเสมอ)</span>
|
||||
<p class="text-xs text-gray-500 mt-0.5">คุกกี้ที่จำเป็นสำหรับการทำงานของเว็บไซต์</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-not-allowed">
|
||||
<input type="checkbox" checked disabled class="sr-only peer" />
|
||||
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-green-500 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-green-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between p-4 bg-gray-50 rounded-lg">
|
||||
<div>
|
||||
<span class="font-medium text-gray-900">วิเคราะห์การใช้งาน</span>
|
||||
<p class="text-xs text-gray-500 mt-0.5">ช่วยให้เราเข้าใจว่าผู้ใช้งานใช้เว็บไซต์อย่างไร</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" id="consent-analytics" class="sr-only peer" />
|
||||
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-green-500 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-green-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between p-4 bg-gray-50 rounded-lg">
|
||||
<div>
|
||||
<span class="font-medium text-gray-900">การตลาด</span>
|
||||
<p class="text-xs text-gray-500 mt-0.5">ใช้สำหรับการตลาดและโฆษณา</p>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" id="consent-marketing" class="sr-only peer" />
|
||||
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-green-500 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-green-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex flex-col sm:flex-row gap-3">
|
||||
<button
|
||||
id="consent-save"
|
||||
class="flex-1 px-5 py-2.5 text-sm font-medium text-white bg-green-600 rounded-lg hover:bg-green-700 transition-colors focus:outline-none focus:ring-2 focus:ring-green-500"
|
||||
>
|
||||
บันทึกการตั้งค่า
|
||||
</button>
|
||||
<button
|
||||
id="consent-close"
|
||||
class="px-5 py-2.5 text-sm font-medium text-gray-700 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors focus:outline-none focus:ring-2 focus:ring-gray-400"
|
||||
>
|
||||
ยกเลิก
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const POLICY_VERSION = '1.0';
|
||||
const STORAGE_KEY = 'dealplustech_consent';
|
||||
|
||||
function generateSessionId(): string {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||||
const r = Math.random() * 16 | 0;
|
||||
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
function getSessionId(): string {
|
||||
let sessionId = localStorage.getItem('dealplustech_session');
|
||||
if (!sessionId) {
|
||||
sessionId = generateSessionId();
|
||||
localStorage.setItem('dealplustech_session', sessionId);
|
||||
}
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
function getConsent(): { essential: boolean; analytics: boolean; marketing: boolean } | null {
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
if (stored) {
|
||||
try {
|
||||
return JSON.parse(stored);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function saveConsent(consent: { essential: boolean; analytics: boolean; marketing: boolean }) {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(consent));
|
||||
}
|
||||
|
||||
function applyConsent(consent: { analytics: boolean; marketing: boolean }) {
|
||||
if (consent.analytics) {
|
||||
document.body.classList.add('analytics-enabled');
|
||||
} else {
|
||||
document.body.classList.remove('analytics-enabled');
|
||||
}
|
||||
if (consent.marketing) {
|
||||
document.body.classList.add('marketing-enabled');
|
||||
} else {
|
||||
document.body.classList.remove('marketing-enabled');
|
||||
}
|
||||
|
||||
window.dispatchEvent(new CustomEvent('consent-updated', { detail: consent }));
|
||||
}
|
||||
|
||||
async function logConsent(consent: { essential: boolean; analytics: boolean; marketing: boolean }) {
|
||||
try {
|
||||
await fetch('/api/consent', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
sessionId: getSessionId(),
|
||||
essential: consent.essential,
|
||||
analytics: consent.analytics,
|
||||
marketing: consent.marketing,
|
||||
policyVersion: POLICY_VERSION,
|
||||
}),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to log consent:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function openModal() {
|
||||
const modal = document.getElementById('consent-preferences-modal');
|
||||
const analyticsCheckbox = document.getElementById('consent-analytics') as HTMLInputElement;
|
||||
const marketingCheckbox = document.getElementById('consent-marketing') as HTMLInputElement;
|
||||
|
||||
const existingConsent = getConsent();
|
||||
if (existingConsent) {
|
||||
analyticsCheckbox.checked = existingConsent.analytics;
|
||||
marketingCheckbox.checked = existingConsent.marketing;
|
||||
} else {
|
||||
analyticsCheckbox.checked = false;
|
||||
marketingCheckbox.checked = false;
|
||||
}
|
||||
|
||||
modal?.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
const modal = document.getElementById('consent-preferences-modal');
|
||||
modal?.classList.add('hidden');
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
const analyticsCheckbox = document.getElementById('consent-analytics') as HTMLInputElement;
|
||||
const marketingCheckbox = document.getElementById('consent-marketing') as HTMLInputElement;
|
||||
|
||||
const consent = {
|
||||
essential: true,
|
||||
analytics: analyticsCheckbox.checked,
|
||||
marketing: marketingCheckbox.checked,
|
||||
};
|
||||
|
||||
saveConsent(consent);
|
||||
await logConsent(consent);
|
||||
applyConsent(consent);
|
||||
closeModal();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const modal = document.getElementById('consent-preferences-modal');
|
||||
const backdrop = document.getElementById('consent-modal-backdrop');
|
||||
const saveBtn = document.getElementById('consent-save');
|
||||
const closeBtn = document.getElementById('consent-close');
|
||||
|
||||
window.addEventListener('open-consent-preferences', openModal);
|
||||
|
||||
backdrop?.addEventListener('click', closeModal);
|
||||
closeBtn?.addEventListener('click', closeModal);
|
||||
saveBtn?.addEventListener('click', handleSave);
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user