123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- <script lang="typescript" context="module">
- import type { AppSession, PageData, PreloadContext } from "src/utils/session";
- import type { Option } from "@shared/common/async_utils";
- import type { MDText } from "./md";
- import type { VerifyInfo } from "./verify";
- export async function preload(
- this: PreloadContext,
- { path }: PageData,
- session: AppSession
- ) {
- const mdResult = await this.fetch("/rules/md", { credentials: "include" });
- const md = (await mdResult.json()) as Option<MDText, { error: string }>;
- const verifyReusult = await this.fetch("/rules/verify", { credentials: "include" });
- const verify = (await verifyReusult.json()) as VerifyInfo;
- return {
- rulesText: md.ok ? md.text : "",
- sitekey: verify.captchaSitekey,
- verified: verify.userVerified,
- needsCaptcha: verify.needsCaptcha
- };
- }
- </script>
- <script lang="typescript">
- import { Converter } from "showdown";
- import Icon from "svelte-awesome/components/Icon.svelte";
- import { faSpinner } from "@fortawesome/free-solid-svg-icons";
- import { fade } from "svelte/transition";
- import type { VerifyRequest } from "./verify";
- export let rulesText: string = "";
- export let sitekey: string = "";
- export let verified!: boolean;
- export let needsCaptcha!: boolean;
- let showVerify: boolean = false;
- const spinner = (faSpinner as unknown) as undefined;
- let htmlContent = new Converter().makeHtml(rulesText);
- enum State {
- None,
- Verify,
- Error,
- Message,
- }
- let state: State = State.None;
- let message: string = "";
- async function onVerified(e: { key: string }) {
- state = State.Verify;
- const result = await fetch("/rules/verify", {
- credentials: "include",
- method: "post",
- headers: {
- Accept: "application/json",
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ captchaResponse: e.key } as VerifyRequest),
- });
- const opt = (await result.json()) as Option<unknown, { error: string }>;
- if (!opt.ok) {
- state = State.Error;
- message = opt.error;
- } else {
- state = State.Message;
- message = "Verification done! Welcome to the server!";
- }
- }
- function onExpired() {
- state = State.Error;
- message = "Captcha expired, please solve it again";
- }
- function onError(error: string) {
- state = State.Error;
- message = `${error}; Please try refreshing the page.`;
- }
- </script>
- <style>
- @import "./markdown-dark.css";
- .message {
- @apply text-white;
- }
- .error {
- @apply text-red-600;
- }
- .verify-button {
- @apply text-gray-200 font-bold;
- }
- </style>
- <svelte:head>
- <title>Rules</title>
- </svelte:head>
- <div class="viewport md-dark md-body">
- <div>
- {@html htmlContent}
- </div>
- {#if !verified}
- <div class="flex flex-col flex-wrap items-center">
- <form class="py-4">
- <input type="checkbox" id="show-verify" bind:checked={showVerify} disabled={state != State.None} />
- <label for="show-verify">I understand these rules and agree to abide to
- them</label>
- </form>
- {#if showVerify}
- {#if needsCaptcha}
- <h-captcha site-key={sitekey} dark on:verified={onVerified} on:expired={onExpired} on:error={onError} />
- {:else}
- <button class="verify-button" on:click={() => void onVerified({ key: "" })}>Verify</button>
- {/if}
- {/if}
- <div class="py-2 pointer-events-none select-none">
- {#if state == State.Verify}
- <span transition:fade={{ duration: 50 }}><Icon data={spinner} spin />
- Verifying</span>
- {:else if state == State.Error || state == State.Message}
- <span
- class:message={state == State.Message}
- class:error={state == State.Error}>{message}</span>
- {/if}
- </div>
- </div>
- {/if}
- </div>
|