feat: midterm shit done
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
<script setup>
|
||||
import { ref, computed, defineProps } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { uploadAvatar } from '../../lib/api';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
|
||||
const props = defineProps({
|
||||
profile: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const router = useRouter();
|
||||
|
||||
const jwt = authStore.jwt;
|
||||
|
||||
const avatarFile = ref(null);
|
||||
const avatarError = ref('');
|
||||
|
||||
const onFileChange = (event) => {
|
||||
avatarFile.value = event.target.files[0];
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
avatarError.value = '';
|
||||
|
||||
if (!avatarFile.value) {
|
||||
avatarError.value = 'Avatar is required.';
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatarFile.value.size > 2 * 1024 * 1024) {
|
||||
avatarError.value = 'Avatar must be less than 2MB.';
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatarFile.value.type !== 'image/jpeg' && avatarFile.value.type !== 'image/png') {
|
||||
avatarError.value = 'Avatar must be a JPG or PNG image.';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await uploadAvatar(avatarFile.value, jwt);
|
||||
alert('Avatar uploaded successfully!');
|
||||
// After successful upload, reload this page
|
||||
router.go(0);
|
||||
} catch (error) {
|
||||
alert("Avatar upload failed: " + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
const avatarUrl = computed(() => {
|
||||
if (avatarFile.value) {
|
||||
return URL.createObjectURL(avatarFile.value);
|
||||
}
|
||||
|
||||
return props.profile?.avatar ? import.meta.env.VITE_R2_BASE_URL + props.profile.avatar : '';
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form @submit.prevent="onSubmit">
|
||||
<fieldset class="ts-fieldset">
|
||||
<legend class="ts-legend">Update Profile</legend>
|
||||
<div class="ts-wrap is-vertical">
|
||||
<div class="ts-control">
|
||||
<div class="label">Username</div>
|
||||
<div class="content is-fluid">
|
||||
<div class="ts-input">
|
||||
<input type="text" name="username" placeholder="Username" :value="props.profile?.username" readonly disabled />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ts-control">
|
||||
<div class="label">Avatar</div>
|
||||
<div class="content is-fluid">
|
||||
<div v-if="avatarUrl">
|
||||
<img :src="avatarUrl" alt="Avatar" style="max-width: 100px; max-height: 100px;" />
|
||||
</div>
|
||||
<div class="ts-file" :class="{'is-negative': avatarError}">
|
||||
<input type="file" accept="image/jpeg, image/png" @change="onFileChange" />
|
||||
</div>
|
||||
<div class="ts-text is-small is-negative" v-if="avatarError">{{ avatarError }}</div>
|
||||
<div class="ts-text is-small">Avatar must be a JPG or PNG image less than 2MB.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ts-wrap has-top-spaced is-end-aligned">
|
||||
<button class="ts-button" type="submit">Update</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.ts-error {
|
||||
color: red;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user