Add card saving and deleting
Some checks are pending
Build / build (push) Waiting to run

This commit is contained in:
Trenton Zimmer
2024-10-27 23:03:51 -04:00
parent 386fc454fe
commit 4781382d51
6 changed files with 98 additions and 24 deletions

View File

@@ -46,7 +46,7 @@ export const getButtonColor = (
lightDark: "ring-gray-200 dark:ring-gray-500",
contrast: "ring-gray-300 dark:ring-gray-400",
success: "ring-emerald-300 dark:ring-emerald-700",
danger: "ring-red-300 dark:ring-red-700",
danger: "ring-red-300 dark:ring-red-900",
warning: "ring-yellow-300 dark:ring-yellow-700",
info: "ring-blue-300 dark:ring-blue-800",
},
@@ -89,8 +89,8 @@ export const getButtonColor = (
lightDark: "border-gray-100 dark:border-slate-800",
contrast: "border-gray-800 dark:border-white",
success: "border-emerald-600 dark:border-emerald-800",
danger: "border-red-600 dark:border-red-500",
warning: "border-yellow-600 dark:border-yellow-900",
danger: "border-red-600 dark:border-ruby-950",
warning: "border-yellow-600 dark:border-yellow-950",
info: "border-blue-600 dark:border-blue-950",
},
text: {

View File

@@ -20,7 +20,7 @@ import BaseButton from "@/components/BaseButton.vue";
</div>
<div class="md:py-2">
<BaseButton
color="info"
color="warning"
href="https://paypal.me/trmazi"
label="Donate"
:icon="mdiCash"

View File

@@ -59,8 +59,8 @@ function getCardStyle(game) {
<div class="space-y-3 text-center md:text-left lg:mx-12">
<div class="space-y-2 md:space-y-0">
<h1 v-if="!useSmall" class="text-2xl md:text-xl lg:text-2xl">
{{ greeting.header[0] }}
<b>{{ mainStore.userName }} </b>{{ greeting.header[1] }}
{{ greeting.header[0] }}<b>{{ mainStore.userName }} </b
>{{ greeting.header[1] }}
</h1>
<h1 v-if="useSmall" class="text-3xl md:text-4xl">
<b>{{ mainStore.userName }}</b>

View File

@@ -56,3 +56,37 @@ export async function APIUpdatePassword(
throw error;
}
}
export async function APIGetCards() {
try {
const data = await mainStore.callApi(`/user/card`);
return data.cards;
} catch (error) {
console.log("Error fetching cards:", error);
throw error;
}
}
export async function APIPutCard(cardId) {
try {
const data = await mainStore.callApi(`/user/card`, "POST", {
cardId: cardId,
});
return data;
} catch (error) {
console.log("Error adding card:", error);
throw error;
}
}
export async function APIDeleteCard(cardId) {
try {
const data = await mainStore.callApi(`/user/card`, "DELETE", {
cardId: cardId,
});
return data;
} catch (error) {
console.log("Error deleting card:", error);
throw error;
}
}

View File

@@ -75,6 +75,15 @@ export const useMainStore = defineStore("main", {
},
async callApi(endpoint, method = "GET", data = null, extraHeaders = {}) {
if (method === "DELETE") {
const confirmed = window.confirm("Are you really?");
if (!confirmed) {
this.isSaving = false;
this.isLoading = false;
return null; // Exit if user does not confirm
}
}
const apiServer = import.meta.env.VITE_API_URL;
const apiKey = import.meta.env.VITE_API_KEY;
let loadingTimeout;
@@ -263,16 +272,6 @@ export const useMainStore = defineStore("main", {
}
},
async getCards() {
try {
const data = await this.callApi(`/user/cards`);
return data.cards;
} catch (error) {
console.log("Error fetching cards:", error);
throw error;
}
},
async getArcade(arcadeId) {
try {
const data = await this.callApi(`/arcade/${arcadeId}`);

View File

@@ -15,23 +15,58 @@ import FormControl from "@/components/FormControl.vue";
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
import SectionTitleLine from "@/components/SectionTitleLine.vue";
import { useMainStore } from "@/stores/main";
const mainStore = useMainStore();
import { APIGetCards, APIPutCard, APIDeleteCard } from "@/stores/api/account";
var cardData = ref([]);
const cardLoading = ref(false);
const cardForm = reactive({
newCard: null,
});
onMounted(async () => {
async function loadCards() {
cardData.value = null;
try {
const data = await mainStore.getCards();
const data = await APIGetCards();
cardData.value = data;
} catch (error) {
console.error("Failed to fetch card data:", error);
}
}
onMounted(async () => {
await loadCards();
});
function cardInput(event) {
var input = event.target.value;
input = input.replace(/[^A-Za-z0-9]/g, "");
// Format the input to XXXX-XXXX-XXXX-XXXX
input = input
.toUpperCase()
.replace(/(.{4})/g, "$1-")
.replace(/-$/, "");
cardForm.newCard = input;
}
async function submitCard() {
cardLoading.value = true;
const response = await APIPutCard(cardForm.newCard);
if (response.status == "success") {
cardForm.newCard = null;
cardLoading.value = false;
await loadCards();
}
}
async function deleteCard(cardId) {
const response = await APIDeleteCard(dashCode(cardId));
if (response.status == "success") {
await loadCards();
}
}
const copyToClipboard = (text) => {
navigator.clipboard
.writeText(text)
@@ -54,7 +89,7 @@ const copyToClipboard = (text) => {
title="Register Card"
main
/>
<CardBox is-form class="row-span-2 mb-6">
<CardBox is-form class="row-span-2 mb-6" @submit.prevent="submitCard()">
<FormField
label="Card ID"
help="The 16 character ACCESS CODE. If your card is dated after 2016, you'll need to get the ACCESS CODE from a game."
@@ -65,16 +100,17 @@ const copyToClipboard = (text) => {
name="cardId"
type="card"
placeholder="XXXX-XXXX-XXXX-XXXX"
minlength="16"
minlength="19"
maxlength="19"
required
@input="cardInput"
/>
</FormField>
<template #footer>
<BaseButton type="submit" color="success" label="Add Card" />
<BaseIcon
v-if="passwordLoading"
v-if="cardLoading"
:path="mdiLoading"
color="text-yellow-500"
class="animate animate-spin"
@@ -95,6 +131,7 @@ const copyToClipboard = (text) => {
</div>
<div
v-if="cardData"
class="grid grid-cols-1 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-6"
>
<div
@@ -120,7 +157,11 @@ const copyToClipboard = (text) => {
label="Copy NFC-ID"
@click="copyToClipboard(card.id)"
/>
<BaseButton color="danger" label="Delete" />
<BaseButton
color="danger"
label="Delete"
@click="deleteCard(card.encoded)"
/>
</div>
</div>
</div>