Skip to content

Commit

Permalink
feat: update
Browse files Browse the repository at this point in the history
  • Loading branch information
supersonictw committed Nov 14, 2024
1 parent 262ec8f commit d140108
Show file tree
Hide file tree
Showing 9 changed files with 721 additions and 72 deletions.
32 changes: 29 additions & 3 deletions src/plugins/turnstile.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const {
VITE_TURNSTILE_SITE_KEY: turnstileSiteKey,
} = import.meta.env;
import {onMounted, onBeforeUnmount} from "vue";

const {VITE_TURNSTILE_SITE_KEY: turnstileSiteKey} = import.meta.env;
const scriptSourceUrl = "https://challenges.cloudflare.com/turnstile/v0/api.js?onload=loadTurnstile";

const turnstileScript = document.createElement("script");
Expand All @@ -16,6 +15,9 @@ turnstileScript.setAttribute("src", scriptSourceUrl);
* @returns {void}
*/
export function loadTurnstile(selector, callback) {
if (!turnstileSiteKey) {
throw new Error("turnstileSiteKey is required for loadTurnstile");
}
document.head.appendChild(turnstileScript);
window.loadTurnstile = () => {
window.turnstile.render(selector, {
Expand All @@ -34,3 +36,27 @@ export function loadTurnstile(selector, callback) {
export function unloadTurnstile() {
document.head.removeChild(turnstileScript);
}

/**
* Vue 3 composition function to use the Turnstile widget.
* @module turnstile
* @function
* @param {string} selector - The CSS selector to render the Turnstile widget.
* @returns {Promise<string>} The promise that resolves when the Turnstile widget is solved.
*/
export function useTurnstile(selector) {
if (!selector) {
throw new Error("selector is required for useTurnstile");
}
return new Promise((resolve) => {
// Attach the Turnstile script when the component is mounted.
onMounted(
() => loadTurnstile(selector, resolve),
);

// Detach the Turnstile script when the component is unmounted.
onBeforeUnmount(
() => unloadTurnstile(),
);
});
}
8 changes: 6 additions & 2 deletions src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ const routes = [
component: () => import("../views/RoomManageView.vue"),
},
{
path: "/submissions/:roomCode",
component: () => import("../views/SubmissionView.vue"),
path: "/rooms/:roomCode/submissions",
component: () => import("../views/RoomSubmissionView.vue"),
},
{
path: "/ti/g2/:roomCode",
component: () => import("../views/TicketView.vue"),
},
{
path: "/terms",
Expand Down
2 changes: 1 addition & 1 deletion src/views/HomeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
class="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-lime-600 hover:bg-lime-600 md:py-4 md:text-lg md:px-10"
@click="onClickRoomCreate"
>
我的社群不想要廣告,我要 Freya
我的社群不想要廣告,我要安裝芙蕾雅
</button>
</div>
<div class="mt-3 sm:mt-0 sm:ml-3">
Expand Down
157 changes: 134 additions & 23 deletions src/views/RoomCreateView.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<div>
<div class="flex flex-wrap w-full justify-center bg-lime-600 py-20">
<div :style="backgroundStyle" />
<div class="absolute top-36 flex w-full justify-center">
<div
v-if="step === 1"
class="max-w-md mx-3 my-5 py-4 px-8 bg-white shadow-lg rounded-lg"
Expand All @@ -21,7 +22,7 @@
</router-link>
</p>
<div class="flex justify-end mt-4">
<div class="flex justify-end mt-8">
<button
class="flex items-center justify-center bg-green-700 hover:bg-green-800 text-white font-bold py-2 px-4 rounded-full"
@click="onClickNext"
Expand All @@ -40,15 +41,15 @@
<p class="mt-2 text-gray-600">
請輸入您的社群邀請網址:
</p>
<div class="w-full mt-2 text-gray-600 flex rounded bg-white shadow-md">
<div class="w-full my-8 text-gray-600 flex rounded bg-white shadow-md">
<input
v-model="pageUrl"
v-model="roomData.pageUrl"
placeholder="https://line.me/ti/g2/J7bTfoHgmfgc42C9baJNs2gwH00kAMd9QfJDsQ"
class="w-full border-none bg-transparent px-4 py-1 text-gray-900 outline-none focus:outline-none"
class="w-full border-none bg-transparent px-4 py-1 text-gray-900 outline-none focus:outline-none text-gray-500"
type="text"
>
</div>
<div class="flex justify-end mt-4">
<div class="flex justify-end mt-8">
<button
class="flex items-center justify-center bg-green-700 hover:bg-green-800 text-white font-bold py-2 px-4 rounded-full"
@click="onClickRequest"
Expand All @@ -65,19 +66,50 @@
v-else-if="step === 3"
class="max-w-md mx-3 my-5 py-4 px-8 bg-white shadow-lg rounded-lg"
>
<div class="flex justify-center md:justify-end -mt-16">
<img
:alt="roomData.label"
:src="roomData.backgroundImage"
class="w-20 h-20 object-cover rounded-full border-2 border-white-500"
>
</div>
<h2 class="text-gray-800 text-3xl font-semibold">
{{ roomProfile.label }}
{{ roomData.label }}
</h2>
<p class="mt-2 text-gray-600">
這是您的社群嗎?請複製以下訊息,並貼到您的社群簡介欄位中。
這是您的社群嗎?
</p>
<p class="mt-2 text-gray-600">
請複製以下訊息,並貼到您的社群簡介欄位中:
</p>
<div class="w-full my-8 text-gray-600 flex rounded bg-white shadow-md">
<textarea
:value="verifyMessage"
class="w-full border-none bg-transparent px-4 py-1 text-gray-900 outline-none focus:outline-none text-gray-500 resize-none"
readonly
/>
<button
title="複製"
class="m-2 rounded px-4 py-2 font-semibold"
@click="onClickCopyVerifyMessage"
>
<check-icon
v-if="isCopy"
class="h-6 w-6"
/>
<document-duplicate-icon
v-else
class="h-6 w-6"
/>
</button>
</div>
<p class="mt-2 text-gray-600">
這份訊息將用來引導申請人轉往使用 Freya 芙蕾雅系統加入您的社群。
</p>
<div class="flex justify-end mt-4">
<p class="mt-2 text-gray-600">
同時用以驗證您對於該社群是否具有管理權限。
</p>
<div class="flex justify-end mt-8">
<button
class="flex items-center justify-center bg-green-700 hover:bg-green-800 text-white font-bold py-2 px-4 rounded-full"
@click="onClickVerify"
Expand All @@ -95,17 +127,33 @@
class="max-w-md mx-3 my-5 py-4 px-8 bg-white shadow-lg rounded-lg"
>
<h2 class="text-gray-800 text-3xl font-semibold">
歡迎!
歡迎加入芙蕾雅!<br>
<span class="font-normal">
{{ roomData.label }}
</span>
</h2>
<div class="mt-2">
<img
:alt="roomData.label"
:src="roomData.backgroundImage"
class="w-20 h-20 object-cover rounded-full border-2 border-white-500"
>
</div>
<p class="mt-2 text-gray-600">
{{ roomProfile.label }}
耶!感謝 {{ profile.nickname }}
</p>
<div class="flex justify-end mt-4">
<p class="mt-2 text-gray-600">
恭喜您已經成功為
{{ roomData.label }}
設定 Freya 芙蕾雅,
擺脫惡意廣告夢魘啦!
</p>
<div class="flex justify-end mt-8">
<button
class="flex items-center justify-center bg-lime-700 hover:bg-lime-800 text-white font-bold py-2 px-4 rounded-full"
@click="onClickRefresh"
@click="onClickRoomManage"
>
查看社群
前往社群管理
</button>
</div>
</div>
Expand All @@ -119,7 +167,7 @@
<p class="mt-2 text-gray-600">
未預期的錯誤發生,請重新整理頁面。
</p>
<div class="flex justify-end mt-4">
<div class="flex justify-end mt-8">
<button
class="flex items-center justify-center bg-red-700 hover:bg-red-800 text-white font-bold py-2 px-4 rounded-full"
@click="onClickRefresh"
Expand All @@ -135,29 +183,56 @@

<script setup>
import {ref, computed, reactive} from "vue";
import {useRouter} from "vue-router";
import {useClient} from "../clients/freya.js";
import {useProfile} from "../plugins/profile.js";
import {
CheckIcon,
DocumentDuplicateIcon,
} from "@heroicons/vue/24/outline";
import ToastModal from "../components/ToastModal.vue";
import LoadingCircleIcon from "../components/LoadingCircleIcon.vue";
const step = ref(1);
const pageUrl = ref("");
const {
VITE_FREYA_INTE_HOST: freyaInteHost,
} = import.meta.env;
const router = useRouter();
const profile = useProfile();
const isLoad = ref(false);
const isCopy = ref(false);
const step = ref(1);
const code = ref("");
const hash = ref("");
const statusMessage = ref("");
const verifyMessage = computed(() => {
return `${code.value}`;
return `煩請前往:\n${freyaInteHost}/#/ti/g2/${code.value}\n` +
"遵循流程取得加入代碼,並在此填入,感謝您\n" +
"(⚠️請勿回覆加入代碼以外的答案)";
});
const roomProfile = reactive({
const roomData = reactive({
code: "",
label: "",
members: "",
description: "",
backgroundImage: "",
pageUrl: "",
});
const backgroundStyle = computed(() => {
const {backgroundImage} = roomData;
return {
"backgroundImage": `url(${backgroundImage})`,
"filter": "brightness(0.3)",
"height": "100vh",
};
});
const onClickNext = () => {
Expand All @@ -168,22 +243,58 @@ const onClickRefresh = () => {
location.reload();
};
const onClickRoomManage = () => {
const {code: roomCode} = roomData;
router.push(`/rooms/${roomCode}`);
};
const onClickCopyVerifyMessage = async () => {
if (!navigator.clipboard) {
statusMessage.value = "您的瀏覽器不支援複製功能";
return;
}
try {
await navigator.clipboard.
writeText(verifyMessage.value);
statusMessage.value = "已複製代碼";
isCopy.value = true;
setTimeout(() => {
isCopy.value = false;
}, 3000);
} catch (error) {
statusMessage.value = "無法複製代碼";
console.error(error);
}
};
const onClickRequest = async () => {
if (!pageUrl.value) {
if (!roomData.pageUrl) {
statusMessage.value = "請輸入社群加入網址。";
return;
}
if (!roomData.pageUrl.startsWith("https://")) {
const {pageUrl: pageUrlMessage} = roomData;
const urls = pageUrlMessage.match(/https?:\/\/\S+/);
if (urls.length !== 1) {
statusMessage.value = "請輸入正確的社群加入網址。";
return;
}
roomData.pageUrl = urls[0];
}
isLoad.value = true;
try {
const client = useClient();
const result = await client.post("rooms", {
json: {
url: pageUrl.value,
url: roomData.pageUrl,
},
}).json();
Object.assign(roomProfile, result.room);
Object.assign(roomData, result.room);
code.value = result.code;
hash.value = result.hash;
Expand All @@ -200,7 +311,7 @@ const onClickVerify = async () => {
const client = useClient();
await client.patch("rooms", {
json: {
url: pageUrl.value,
url: roomData.pageUrl,
code: code.value,
hash: hash.value,
},
Expand Down
Loading

0 comments on commit d140108

Please sign in to comment.