Initialer Laravel Commit für BetiX
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled

This commit is contained in:
2026-04-04 18:01:50 +02:00
commit 0280278978
374 changed files with 65210 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import PolicyLayout from './_PolicyLayout.vue';
const updated = '2026-03-01T20:20:00Z';
const intro = 'Our AML/CTF approach: KYC verification, transaction monitoring, reporting obligations, and record-keeping.';
const metaDescription = 'BetiX AML Policy: KYC, monitoring for suspicious activity, reporting to authorities, record-keeping, and prohibited behavior.';
</script>
<template>
<PolicyLayout title="AML Policy" :updated="updated" :intro="intro" :metaDescription="metaDescription">
<p>This AntiMoney Laundering (AML) Policy outlines the measures BetiX takes to prevent money laundering and terrorist financing.</p>
<h2>1. Verification (KYC)</h2>
<p>We may request identity and address verification documents before allowing certain transactions.</p>
<h2>2. Monitoring</h2>
<p>Transactions are monitored for suspicious activity. We may suspend accounts while reviews are conducted.</p>
<h2>3. Reporting</h2>
<p>Where legally required, we report suspicious activity to competent authorities and cooperate with investigations.</p>
<h2>4. Prohibited activity</h2>
<p>Use of stolen funds, chargeback abuse, or attempts to obfuscate source of funds is strictly prohibited.</p>
</PolicyLayout>
</template>

View File

@@ -0,0 +1,30 @@
<script setup lang="ts">
import PolicyLayout from './_PolicyLayout.vue';
const updated = '2026-03-01T20:20:00Z';
const intro = 'Rules for bonuses, free spins, and promotions: eligibility, wagering, abuse prevention, and payout conditions.';
const metaDescription = 'BetiX Bonus Policy: eligibility, wagering requirements, bonus abuse rules, payout conditions, and bonus types.';
</script>
<template>
<PolicyLayout title="Bonus Policy" :updated="updated" :intro="intro" :metaDescription="metaDescription">
<p>This Bonus Policy sets out the rules for bonuses, free spins, and promotional offers on BetiX.</p>
<h2>1. Eligibility</h2>
<ul>
<li>Bonuses are limited to one per person, household, IP, device, or payment method unless stated otherwise.</li>
<li>We may require KYC verification before or after awarding a bonus.</li>
</ul>
<h2>2. Wagering</h2>
<ul>
<li>Unless otherwise stated, wagering requirements apply and must be completed within the specified time window.</li>
<li>Different games may contribute differently towards wagering.</li>
</ul>
<h2>3. Abuse</h2>
<p>Bonus abuse (e.g., hedging, multiple accounts, riskfree bets) may lead to confiscation and account action.</p>
<h2>4. Changes</h2>
<p>We reserve the right to modify, suspend, or withdraw any offer at our discretion.</p>
</PolicyLayout>
</template>

View File

@@ -0,0 +1,27 @@
<script setup lang="ts">
import PolicyLayout from './_PolicyLayout.vue';
const updated = '2026-03-01T20:20:00Z';
const intro = 'How and why we use cookies and similar technologies, how you can control them, and the impact on your experience.';
const metaDescription = 'BetiX Cookie Policy: types of cookies, consent management, providers, and how to control cookies in your browser.';
</script>
<template>
<PolicyLayout title="Cookie Policy" :updated="updated" :intro="intro" :metaDescription="metaDescription">
<p>This Cookie Policy explains how BetiX uses cookies and similar technologies to recognize you when you visit our site and use our services.</p>
<h2>1. What are cookies?</h2>
<p>Cookies are small text files stored on your device to help websites function and improve your experience.</p>
<h2>2. How we use cookies</h2>
<ul>
<li>Strictly necessary cookies for authentication and security (e.g., CSRF, session).</li>
<li>Performance cookies to measure site usage and improve features.</li>
<li>Preference cookies to remember your settings (e.g., theme, language).</li>
</ul>
<h2>3. Managing cookies</h2>
<p>You can control cookies through your browser settings. Disabling some cookies may affect site functionality.</p>
<div class="callout">For questions about cookies, contact Support.</div>
</PolicyLayout>
</template>

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import PolicyLayout from './_PolicyLayout.vue';
const updated = '2026-03-01T20:20:00Z';
const intro = 'How to raise complaints, how we handle them, escalation routes, and timelines.';
const metaDescription = 'BetiX Dispute Resolution Policy: internal complaints process, escalation to ADR, timelines, and evidence requirements.';
</script>
<template>
<PolicyLayout title="Dispute Resolution Policy" :updated="updated" :intro="intro" :metaDescription="metaDescription">
<p>This policy explains how to raise and resolve disputes with BetiX fairly and efficiently.</p>
<h2>1. Contact Support first</h2>
<p>Please contact our Support team with full details (time, game, bet ID, screenshots if possible). Most issues are resolved quickly.</p>
<h2>2. Escalation</h2>
<p>If you are not satisfied with the initial response, request an escalation. A senior specialist will review your case.</p>
<h2>3. External ADR</h2>
<p>Where required by local regulation, you may refer your complaint to an approved Alternative Dispute Resolution (ADR) provider. We will cooperate in good faith.</p>
<h2>4. Time limits</h2>
<p>Submit disputes within 30 days of the event. Delayed submissions may be harder to investigate.</p>
</PolicyLayout>
</template>

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import PolicyLayout from './_PolicyLayout.vue';
const updated = '2026-03-01T20:20:00Z';
const intro = 'How we collect, use, share, and protect your personal data, and what rights you have over it.';
const metaDescription = 'BetiX Privacy Policy: data we collect, purposes, legal bases, recipients, retention, your rights, cookies, and security.';
</script>
<template>
<PolicyLayout title="Privacy Policy" :updated="updated" :intro="intro" :metaDescription="metaDescription">
<p>This Privacy Policy describes how BetiX collects, uses, and protects your personal data in accordance with applicable data protection laws.</p>
<h2>1. Data we collect</h2>
<ul>
<li>Account data: email/username, profile details and preferences.</li>
<li>Usage data: device, IP, user agent, and activity logs for security.</li>
<li>Compliance data: KYC/AML documents where required by law.</li>
</ul>
<h2>2. How we use data</h2>
<ul>
<li>To provide and improve services, ensure security, and meet legal obligations.</li>
<li>To communicate with you about service updates, security, and promotions (where permitted).</li>
</ul>
<h2>3. Your rights</h2>
<p>You may have rights to access, correct, or delete your data, and to object or restrict certain processing, subject to legal exceptions.</p>
<h2>4. Security</h2>
<p>We use technical and organizational measures, including encryption at rest for sensitive fields, to protect your data.</p>
<div class="callout">Contact Support for privacy requests or questions.</div>
</PolicyLayout>
</template>

View File

@@ -0,0 +1,27 @@
<script setup lang="ts">
import PolicyLayout from './_PolicyLayout.vue';
const updated = '2026-03-01T20:20:00Z';
const intro = 'Our commitment to safe play: tools, guidance, and resources to help you stay in control.';
const metaDescription = 'BetiX Responsible Gaming: tools like limits/timeouts/self-exclusion, support resources, and protection of minors.';
</script>
<template>
<PolicyLayout title="Responsible Gaming" :updated="updated" :intro="intro" :metaDescription="metaDescription">
<p>BetiX is committed to responsible gaming. We provide tools and guidance to help you stay in control.</p>
<h2>1. Tools</h2>
<ul>
<li>Deposit, loss, and session limits.</li>
<li>Timeouts and selfexclusion.</li>
<li>Reality checks and session reminders.</li>
</ul>
<h2>2. Selfassessment</h2>
<p>If you feel your gaming is getting out of control, consider taking a break and seeking help from independent organizations.</p>
<h2>3. Support</h2>
<p>Contact our Support to enable limits or selfexclusion. We may require ID verification to process certain requests.</p>
<div class="callout">Help resources: BeGambleAware.org, GamCare.org.uk, and local hotlines in your country.</div>
</PolicyLayout>
</template>

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import PolicyLayout from './_PolicyLayout.vue';
const updated = '2026-03-01T20:20:00Z';
const intro = 'Important information about risks when participating in online gaming and using crypto assets.';
const metaDescription = 'BetiX Risk Warnings: financial loss risk, volatility, responsible play guidance, and legal considerations.';
</script>
<template>
<PolicyLayout title="Risk Warnings" :updated="updated" :intro="intro" :metaDescription="metaDescription">
<p>Online gaming involves financial risk. Please read and understand the following warnings before participating.</p>
<h2>1. Loss risk</h2>
<p>You can lose money. Do not gamble funds you cannot afford to lose.</p>
<h2>2. Volatility</h2>
<p>Outcomes are random; shortterm results can vary widely. Past results do not predict future performance.</p>
<h2>3. Responsible play</h2>
<p>Set limits, take breaks, and seek help if needed. See Responsible Gaming for resources.</p>
<h2>4. Legal</h2>
<p>Make sure participation is legal in your jurisdiction. You are responsible for compliance with local laws.</p>
</PolicyLayout>
</template>

View File

@@ -0,0 +1,47 @@
<script setup lang="ts">
import PolicyLayout from './_PolicyLayout.vue';
const updated = '2026-03-01T20:20:00Z';
const intro = 'The rules that govern your use of BetiX, including eligibility, accounts, payments, bonuses, and more.';
const metaDescription = 'BetiX Terms and Conditions: eligibility, accounts, deposits/withdrawals, bonuses, fair play, liability, termination, and governing law.';
</script>
<template>
<PolicyLayout title="Terms and Conditions" :updated="updated" :intro="intro" :metaDescription="metaDescription">
<p>These Terms and Conditions ("Terms") govern your access to and use of the BetiX platform. By creating an account or using the services, you agree to be bound by these Terms.</p>
<h2>1. Eligibility</h2>
<ul>
<li>You must be at least 18 years old (or the legal age in your jurisdiction) to use our services.</li>
<li>You are solely responsible for ensuring that online gaming is legal in your jurisdiction.</li>
</ul>
<h2>2. Account</h2>
<ul>
<li>You agree to provide accurate information and keep it updated.</li>
<li>You are responsible for safeguarding your credentials and account activity.</li>
</ul>
<h2>3. Fair Play</h2>
<p>Any attempt to cheat, exploit bugs, use bots, multi-accounting, or otherwise gain unfair advantage may result in suspension, confiscation of funds, or permanent ban.</p>
<h2>4. Deposits and Withdrawals</h2>
<ul>
<li>All transactions are subject to AML/KYC checks and risk reviews.</li>
<li>We reserve the right to request additional verification before processing withdrawals.</li>
</ul>
<h2>5. Bonuses</h2>
<p>Bonuses are governed by our separate Bonus Policy. In case of conflict, the Bonus Policy prevails for bonusrelated matters.</p>
<h2>6. Responsible Gaming</h2>
<p>We encourage safe play. Tools for limits, timeouts, and selfexclusion are available. See Responsible Gaming.</p>
<h2>7. Suspension and Termination</h2>
<p>We may suspend or terminate accounts that violate these Terms, regulatory requirements, or present AML/abuse risks.</p>
<h2>8. Changes</h2>
<p>We may update these Terms. Material changes will be announced; continued use constitutes acceptance.</p>
<div class="callout">If you have questions about these Terms, contact Support.</div>
</PolicyLayout>
</template>

View File

@@ -0,0 +1,181 @@
<script setup lang="ts">
import { Head } from '@inertiajs/vue3';
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
import UserLayout from '@/layouts/user/userlayout.vue';
const props = withDefaults(defineProps<{
title: string;
updated?: string;
intro?: string;
metaDescription?: string;
}>(), {
intro: '',
metaDescription: ''
});
const contentRef = ref<HTMLElement | null>(null);
const toc = ref<{ id: string; text: string; level: number }[]>([]);
const activeId = ref<string>('');
const canonical = ref<string>('');
let observer: IntersectionObserver | null = null;
function slugify(text: string): string {
return text
.toLowerCase()
.normalize('NFD').replace(/\p{Diacritic}/gu, '')
.replace(/[^a-z0-9\s-]/g, '')
.trim().replace(/\s+/g, '-').replace(/-+/g, '-');
}
function buildToc() {
if (!contentRef.value) return;
toc.value = [];
const headings = Array.from(contentRef.value.querySelectorAll('h2, h3')) as HTMLElement[];
for (const h of headings) {
if (!h.id) {
h.id = slugify(h.innerText || h.textContent || 'section');
}
// Ensure scroll margin for sticky headers
h.style.scrollMarginTop = '90px';
toc.value.push({ id: h.id, text: h.innerText || h.textContent || '', level: h.tagName === 'H2' ? 2 : 3 });
}
}
function setupObserver() {
if (!contentRef.value) return;
cleanupObserver();
observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
const id = (entry.target as HTMLElement).id;
activeId.value = id;
break;
}
}
}, { root: null, rootMargin: '0px 0px -70% 0px', threshold: [0, 1.0] });
contentRef.value.querySelectorAll('h2, h3').forEach(el => observer!.observe(el));
}
function cleanupObserver() {
if (observer) { observer.disconnect(); observer = null; }
}
function scrollToId(id: string) {
const el = document.getElementById(id);
if (!el) return;
const top = el.getBoundingClientRect().top + window.scrollY - 80; // offset for sticky header
window.scrollTo({ top, behavior: 'smooth' });
}
onMounted(async () => {
await nextTick();
buildToc();
setupObserver();
// compute canonical on client only to avoid SSR/window issues
try {
if (typeof window !== 'undefined' && window?.location) {
canonical.value = window.location.origin + window.location.pathname;
}
} catch {}
// Rebuild if icons/fonts change layout slightly
setTimeout(buildToc, 50);
});
onBeforeUnmount(() => cleanupObserver());
</script>
<template>
<UserLayout>
<Head :title="props.title">
<template #default>
<meta v-if="props.metaDescription" name="description" :content="props.metaDescription" />
<link v-if="canonical" rel="canonical" :href="canonical" />
</template>
</Head>
<section class="policy-wrap">
<div class="policy-grid">
<!-- Desktop Sticky ToC -->
<nav class="toc" :aria-label="$t('policy.toc')">
<div class="toc-title">{{ $t('policy.toc') }}</div>
<ul>
<li v-for="item in toc" :key="item.id" :class="['lvl'+item.level, { active: activeId===item.id }]">
<a :href="`#${item.id}`" @click.prevent="scrollToId(item.id)">{{ item.text }}</a>
</li>
</ul>
</nav>
<div class="policy-card">
<header class="p-head">
<h1 class="p-title">{{ props.title }}</h1>
<div class="p-updated" v-if="props.updated">{{ $t('policy.lastUpdated') }}: {{ new Date(props.updated).toLocaleDateString() }}</div>
<p v-if="props.intro" class="p-intro">{{ props.intro }}</p>
<!-- Mobile ToC toggle -->
<details class="toc-mobile">
<summary>{{ $t('policy.toc') }}</summary>
<ul>
<li v-for="item in toc" :key="item.id" :class="['lvl'+item.level, { active: activeId===item.id }]">
<a :href="`#${item.id}`" @click.prevent="scrollToId(item.id)">{{ item.text }}</a>
</li>
</ul>
</details>
</header>
<div class="p-body" ref="contentRef">
<slot />
</div>
</div>
</div>
</section>
</UserLayout>
</template>
<style scoped>
.policy-wrap { padding: 30px; display: flex; justify-content: center; }
.policy-grid { width: 100%; max-width: 1100px; display: grid; grid-template-columns: 260px 1fr; gap: 20px; }
/* ToC Desktop */
.toc { position: sticky; top: 90px; align-self: start; background: #0a0a0a; border: 1px solid #151515; border-radius: 12px; padding: 14px; height: fit-content; display: none; }
.toc-title { font-size: 12px; font-weight: 900; color: #fff; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 1px; }
.toc ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 6px; }
.toc li a { color: #aaa; text-decoration: none; font-size: 12px; font-weight: 700; display: block; padding: 6px 8px; border-radius: 8px; }
.toc li a:hover, .toc li.active a { color: #fff; background: rgba(0,242,255,0.06); }
.toc li.lvl3 a { padding-left: 18px; font-weight: 600; }
/* Show ToC on desktop */
@media (min-width: 1000px) { .toc { display: block; } }
/* Card */
.policy-card { width: 100%; background: #0a0a0a; border: 1px solid #151515; border-radius: 16px; box-shadow: 0 20px 60px rgba(0,0,0,0.6); overflow:hidden; }
.p-head { padding: 22px 26px; border-bottom: 1px solid #151515; background: linear-gradient(90deg, rgba(0,242,255,0.05), transparent); }
.p-title { margin: 0; font-size: 24px; font-weight: 900; letter-spacing: 1px; text-transform: uppercase; }
.p-updated { margin-top: 6px; font-size: 12px; color: #777; }
.p-intro { margin-top: 10px; font-size: 13px; color: #bbb; }
/* Mobile ToC */
.toc-mobile { display: block; margin-top: 12px; }
.toc-mobile > summary { cursor: pointer; list-style: none; background: #0a0a0a; border: 1px solid #1a1a1a; color: #fff; padding: 8px 10px; border-radius: 8px; font-size: 12px; font-weight: 900; }
.toc-mobile[open] > summary { background: #121212; }
.toc-mobile ul { list-style: none; padding: 8px; margin: 6px 0 0; display: grid; gap: 6px; border: 1px solid #1a1a1a; border-radius: 10px; }
.toc-mobile li a { color: #aaa; text-decoration: none; font-size: 12px; font-weight: 700; display: block; padding: 6px 8px; border-radius: 8px; }
.toc-mobile li a:hover, .toc-mobile li.active a { color: #fff; background: rgba(0,242,255,0.06); }
.toc-mobile li.lvl3 a { padding-left: 18px; font-weight: 600; }
/* Body */
.p-body { padding: 24px 26px; display: grid; gap: 18px; color: #bbb; line-height: 1.8; }
.p-body h2 { color: #fff; font-size: 18px; font-weight: 900; margin: 24px 0 6px; }
.p-body h3 { color: #ddd; font-size: 15px; font-weight: 800; margin: 14px 0 4px; }
.p-body p, .p-body li { font-size: 13px; }
.p-body ul { padding-left: 18px; list-style: disc; }
.callout { background:#0e0e0e; border:1px solid #1f1f1f; padding:12px 14px; border-radius:10px; color:#9bd; }
/* Print */
@media print {
:host, .policy-wrap, .policy-grid, .policy-card, .p-body { all: unset; display: block; }
.toc, .toc-mobile, .p-intro { display: none !important; }
body { color: #000; }
a[href]::after { content: " (" attr(href) ")"; font-size: 10px; }
}
</style>