loagin animation and remove storage

This commit is contained in:
='fauz 2025-10-30 13:19:23 +07:00
parent 59fa8d61c9
commit 581ecdc534
16 changed files with 140 additions and 45 deletions

35
package-lock.json generated
View File

@ -10,11 +10,13 @@
"dependencies": {
"axios": "^1.12.2",
"core-js": "^3.46.0",
"lottie-web": "^5.13.0",
"pinia": "^3.0.3",
"primeicons": "^7.0.0",
"vue": "^3.2.13",
"vue-qrcode-reader": "^5.7.3",
"vue-router": "^4.5.1"
"vue-router": "^4.5.1",
"vue3-lottie": "^3.3.1"
},
"devDependencies": {
"@babel/core": "^7.12.16",
@ -6700,7 +6702,6 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
"license": "MIT"
},
"node_modules/fast-glob": {
@ -8249,7 +8250,6 @@
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
"integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
@ -8820,6 +8820,12 @@
"node": ">=4"
}
},
"node_modules/lottie-web": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.13.0.tgz",
"integrity": "sha512-+gfBXl6sxXMPe8tKQm7qzLnUy5DUPJPKIyRHwtpCpyUEYjHYRJC/5gjUvdkuO2c3JllrPtHXH5UJJK8LRYl5yQ==",
"license": "MIT"
},
"node_modules/lower-case": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
@ -13070,6 +13076,29 @@
"dev": true,
"license": "MIT"
},
"node_modules/vue3-lottie": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/vue3-lottie/-/vue3-lottie-3.3.1.tgz",
"integrity": "sha512-60uQmx4eefi3FdPjAxWnblrgJJjnVTXUA6e4BAI3jGzgOSR76pyzL1rrWDiyPmMFo4mTw4wGTW6Gbkg3HR1mYw==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"klona": "^2.0.6",
"lottie-web": "5.12.2"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"vue": "^3.2"
}
},
"node_modules/vue3-lottie/node_modules/lottie-web": {
"version": "5.12.2",
"resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz",
"integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==",
"license": "MIT"
},
"node_modules/watchpack": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",

View File

@ -11,11 +11,13 @@
"dependencies": {
"axios": "^1.12.2",
"core-js": "^3.46.0",
"lottie-web": "^5.13.0",
"pinia": "^3.0.3",
"primeicons": "^7.0.0",
"vue": "^3.2.13",
"vue-qrcode-reader": "^5.7.3",
"vue-router": "^4.5.1"
"vue-router": "^4.5.1",
"vue3-lottie": "^3.3.1"
},
"devDependencies": {
"@babel/core": "^7.12.16",

BIN
public/images/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,47 @@
<template>
<div v-if="show" class="overlay">
<Vue3Lottie
:animationData="animation"
:height="200"
:width="200"
autoplay
loop
/>
</div>
</template>
<script>
import { Vue3Lottie } from "vue3-lottie";
import animation from "@/assets/images/loading.json";
export default {
name: "LoadingComponent",
components: { Vue3Lottie },
props: {
show: {
type: Boolean,
default: false
}
},
data() {
return {
animation
};
}
};
</script>
<style scoped>
.overlay {
position: fixed;
inset: 0;
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(1px);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
</style>

View File

@ -3,7 +3,8 @@ import App from './App.vue'
import './assets/tailwind.css'
import router from './router'
import { createPinia } from 'pinia'
import Vue3Lottie from 'vue3-lottie'
const pinia = createPinia()
createApp(App).use(pinia).use(router).mount('#app')
createApp(App).use(pinia).use(router).use(Vue3Lottie).mount('#app')

View File

@ -112,7 +112,6 @@ export default {
if (this.pages.length > 0 && this.pages[0].chapter?.manga?.title) {
this.mangaTitle = this.pages[0].chapter.manga.title
}
console.log("Pages :" + JSON.stringify(this.pages))
} catch (err) {
console.error("Gagal memuat halaman:", err)
} finally {

View File

@ -100,13 +100,8 @@ export default {
async loadContent() {
const res = await getChapters(this.id);
this.chapters = res.results;
console.log(this.id)
console.log(this.props)
console.log(res.results);
},
toSynopsis( manga) {
console.log(manga)
router.push({
name: 'manga-sinopsis',
params: { id: manga.id },

View File

@ -136,7 +136,6 @@ export default {
async loadGenres() {
const res = await getGenre();
this.genres = res.results;
console.log(res);
},
onMouseMove(event, name) {
const card = event.currentTarget;

View File

@ -511,7 +511,6 @@ export default {
},
async myPoints(){
const points = await getUserPoint();
// console.log(points)
this.points = points.myPoints;
this.totalTask = points.activeTaskCount;
this.totalDone = points.myActiveTaskCompleteCount;
@ -529,7 +528,7 @@ export default {
try {
const start = new Date(dateValidFrom);
const end = new Date(dateValidTo); // Already UTC-aware
const end = new Date(dateValidTo);
const now = new Date(this.now);
const diffToStart = start - now;
@ -543,8 +542,6 @@ export default {
const seconds = totalSeconds % 60;
return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
}
// 🟢 During event
if (diffToEnd > 0) {
const totalSeconds = Math.floor(diffToEnd / 1000);
const hours = Math.floor(totalSeconds / 3600);
@ -578,8 +575,6 @@ export default {
},
timeLeft(dateFrom, dateTo, timeFrom, timeTo) {
if (!dateFrom || !timeFrom || !dateTo || !timeTo) return "—";
// const now = new Date();
const start = new Date(`${dateFrom}T${timeFrom}`);
const end = new Date(`${dateTo}T${timeTo}`);
const current = this.now;
@ -587,8 +582,6 @@ export default {
const pad = (num) => String(num).padStart(2, "0");
const diffToStart = start - current;
const diffToEnd = end - current;
// 🕰 CASE 1: Before start
if (diffToStart > 0) {
const totalSeconds = Math.floor(diffToStart / 1000);
const hours = Math.floor(totalSeconds / 3600);
@ -605,7 +598,6 @@ export default {
return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
}
// CASE 3: After end
return "❌ Waktu habis";
},
downtimeHours(from, to) {
@ -652,7 +644,6 @@ export default {
// this.startMission(mission);
}
if (mission.task === 'scan-qr') {
console.log(mission)
this.$router.push({
name: 'quest-missions',
params: { id: mission.id } ,
@ -669,7 +660,6 @@ export default {
async startMission(mission) {
if (!mission || !mission.id) {
console.error("Invalid mission", mission);
return;
}
await createMissionLog({
@ -707,7 +697,6 @@ export default {
},
computed: {
currentUser() {
console.log(this.authStore.currentUser)
return this.authStore.currentUser;
}
}

View File

@ -62,6 +62,7 @@
</form>
</div>
</div>
<LoadingComponent :show="isLoading" />
</div>
</template>
@ -87,6 +88,7 @@ export default {
],
selectedCharacter: { name: "Tiger", img: "../images/char/tiger.png" },
selectedProfile: { name: "profile", img: "/images/propic-001.svg" },
isLoading: false,
};
},
methods: {
@ -110,20 +112,25 @@ export default {
import { useAuthStore } from '@/stores/auth'
import { useRouter } from 'vue-router'
import { ref } from 'vue'
import LoadingComponent from '@/components/Loading.vue'
const router = useRouter()
const auth = useAuthStore()
const username = ref('')
const password = ref('')
const error = ref('')
const isLoading = ref(false)
async function login() {
try {
await
isLoading.value = true
await auth.login(username.value, password.value)
router.push('/')
} catch (err) {
error.value = err.message
}finally{
isLoading.value = false;
}
}
</script>
@ -133,4 +140,19 @@ async function login() {
body {
font-family: 'Inter', sans-serif;
}
#loading {
position: fixed;
inset: 0;
}
.overlay {
position: fixed;
inset: 0;
background: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(4px);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
</style>

View File

@ -157,7 +157,6 @@
onMounted(async () => {
if(router.query.mission){
const data = router.query.mission
console.log(data)
mission.value = JSON.parse(data)
}

View File

@ -15,16 +15,13 @@ export const useAuthStore = defineStore('auth', {
},
actions: {
async register(username, password, re_password) {
const response =await axios.post(this.baseUrl + '/auth/users/', {
return await axios.post(this.baseUrl + '/auth/users/', {
username: username,
password: password,
re_password: re_password
});
console.log("✅ Registration success:", response.data);
},
async login(username, password) {
// preparing data
const data = new URLSearchParams()
data.append('grant_type', 'password')
data.append('client_id', this.clientId)
@ -35,7 +32,8 @@ export const useAuthStore = defineStore('auth', {
const response = await axios.post(`${this.baseUrl}`+'/oauth/token/',data.toString(), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}
},
withCredentials:true,
})
const { access_token, refresh_token } = response.data;
@ -48,11 +46,24 @@ export const useAuthStore = defineStore('auth', {
this.refresh_token = refresh_token
this.token = access_token
this.user = user
await this.fetchUser();
// localStorage.setItem('token', this.token)
// localStorage.setItem('user', JSON.stringify(user))
},
async fetchUser() {
try {
const res = await axios.get(`${this.baseUrl}/auth/users/me`, {
headers: {
Authorization: `Bearer ${this.token}`,
},
withCredentials: true,
});
console.log(JSON.stringify(user));
localStorage.setItem('token', this.token)
localStorage.setItem('user', JSON.stringify(user))
console.log("✅ Logged in as:", this.user.username);
this.user = res.data;
} catch (err) {
console.error("❌ fetch user failed", err);
this.user = null;
}
},
async logout() {
if(this.token){
@ -63,6 +74,7 @@ export const useAuthStore = defineStore('auth', {
},
{
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
withCredentials:true
});
}else{
console.log("No token found");
@ -70,16 +82,14 @@ export const useAuthStore = defineStore('auth', {
this.token = null;
this.user = null;
localStorage.removeItem('token')
localStorage.removeItem('user')
// localStorage.removeItem('token')
// localStorage.removeItem('user')
},
restoreSession() {
const savedToken = localStorage.getItem('token')
const savedUser = localStorage.getItem('user')
if (savedToken && savedUser) {
this.token = savedToken
this.user = JSON.parse(savedUser)
async restoreSession() {
try {
await this.fetchUser();
} catch {
console.log("No active session found.");
}
}
}