first commit
This commit is contained in:
578
app/pages/admin/settings/index.vue
Normal file
578
app/pages/admin/settings/index.vue
Normal file
@@ -0,0 +1,578 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Ayarlar</h2>
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-tabs mb-4" id="settingsTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="general-tab" data-bs-toggle="tab" data-bs-target="#general" type="button"
|
||||
role="tab" aria-controls="general" aria-selected="true">Genel Ayarlar</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="hero-tab" data-bs-toggle="tab" data-bs-target="#hero" type="button" role="tab"
|
||||
aria-controls="hero" aria-selected="false">Hero (Banner) Ayarları</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="settingsTabContent">
|
||||
<!-- GENERAL SETTINGS TAB -->
|
||||
<div class="tab-pane fade show active" id="general" role="tabpanel" aria-labelledby="general-tab">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form @submit.prevent="updateSettings">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Site Başlığı</label>
|
||||
<input v-model="settingForm.title" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Slogan</label>
|
||||
<input v-model="settingForm.slogan" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Telefon</label>
|
||||
<input v-model="settingForm.phone" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Email</label>
|
||||
<input v-model="settingForm.email" type="email" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Adres</label>
|
||||
<textarea v-model="settingForm.address" class="form-control" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Harita Embed Code</label>
|
||||
<textarea v-model="settingForm.map_embed" class="form-control" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Copyright Metni</label>
|
||||
<input v-model="settingForm.copyright" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4">SEO Ayarları</h5>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Meta Başlık</label>
|
||||
<input v-model="settingForm.meta_title" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Meta Açıklama</label>
|
||||
<input v-model="settingForm.meta_description" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4">Sosyal Medya</h5>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Facebook</label>
|
||||
<input v-model="settingForm.facebook" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Twitter / X</label>
|
||||
<input v-model="settingForm.x" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Instagram</label>
|
||||
<input v-model="settingForm.instagram" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Linkedin</label>
|
||||
<input v-model="settingForm.linkedin" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Pinterest</label>
|
||||
<input v-model="settingForm.pinterest" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Whatsapp</label>
|
||||
<input v-model="settingForm.whatsapp" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4">Logolar</h5>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Beyaz Logo (Dark Mod için)</label>
|
||||
<input @change="handleFileUpload($event, 'w_logo')" type="file" class="form-control">
|
||||
<div v-if="settingForm.w_logo && typeof settingForm.w_logo === 'string'" class="mt-2">
|
||||
<img :src="config.public.BASE_API_URL + settingForm.w_logo" height="50" class="bg-dark p-1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Siyah Logo (Light Mod için)</label>
|
||||
<input @change="handleFileUpload($event, 'b_logo')" type="file" class="form-control">
|
||||
<div v-if="settingForm.b_logo && typeof settingForm.b_logo === 'string'" class="mt-2">
|
||||
<img :src="config.public.BASE_API_URL + settingForm.b_logo" height="50" class="bg-light border p-1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4">Resim Optimizasyon Ayarları (Logo İçin)</h5>
|
||||
<hr>
|
||||
<div class="row bg-light p-3 rounded mx-1">
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Format</label>
|
||||
<select v-model="imageSettings.format" class="form-select">
|
||||
<option value="avif">AVIF</option>
|
||||
<option value="webp">WEBP</option>
|
||||
<option value="png">PNG</option>
|
||||
<option value="jpg">JPG</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Kalite (1-100)</label>
|
||||
<input v-model="imageSettings.quality" type="number" min="1" max="100" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Genişlik (px)</label>
|
||||
<input v-model="imageSettings.width" type="number" class="form-control" placeholder="Opsiyonel">
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Yükseklik (px)</label>
|
||||
<input v-model="imageSettings.height" type="number" class="form-control" placeholder="Opsiyonel">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-end">
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Kaydet
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HERO SETTINGS TAB -->
|
||||
<div class="tab-pane fade" id="hero" role="tabpanel" aria-labelledby="hero-tab">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center bg-white">
|
||||
<h5 class="mb-0">Hero Listesi</h5>
|
||||
<button class="btn btn-success btn-sm" @click="openHeroModal()"><i class="fas fa-plus me-2"></i> Yeni
|
||||
Ekle</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Resim</th>
|
||||
<th>Başlık</th>
|
||||
<th>Alt Başlıklar</th>
|
||||
<th>Durum</th>
|
||||
<th class="text-end" width="100">İşlemler</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="hero in heroes" :key="hero.ID">
|
||||
<td>
|
||||
<img v-if="hero.image" :src="config.public.BASE_API_URL + hero.image"
|
||||
style="max-width: 60px; height: 40px; object-fit: cover;" class="rounded border">
|
||||
<span v-else>-</span>
|
||||
</td>
|
||||
<td>{{ hero.title }}</td>
|
||||
<td>
|
||||
<small class="d-block text-muted">{{ hero.text1 }}</small>
|
||||
<small class="d-block text-muted">{{ hero.text2 }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge" :class="hero.is_active ? 'bg-success' : 'bg-secondary'">
|
||||
{{ hero.is_active ? 'Aktif' : 'Pasif' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button class="btn btn-outline-primary" @click="openHeroModal(hero)" title="Düzenle">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger" @click="deleteHero(hero.ID)" title="Sil">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="heroes.length === 0">
|
||||
<td colspan="5" class="text-center py-4">Kayıt bulunamadı.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HERO MODAL -->
|
||||
<div class="modal fade" id="heroModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ isEditingHero ? 'Hero Düzenle' : 'Yeni Hero Ekle' }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form @submit.prevent="saveHero">
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Başlık</label>
|
||||
<input v-model="heroForm.title" type="text" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Text 1</label>
|
||||
<input v-model="heroForm.text1" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Text 2</label>
|
||||
<input v-model="heroForm.text2" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Text 4</label>
|
||||
<input v-model="heroForm.text4" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Text 5</label>
|
||||
<input v-model="heroForm.text5" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Renk</label>
|
||||
<div class="input-group">
|
||||
<input v-model="heroForm.color" type="color" class="form-control form-control-color"
|
||||
title="Renk Seçin">
|
||||
<input v-model="heroForm.color" type="text" class="form-control" placeholder="#ffffff">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Durum</label>
|
||||
<div class="form-check form-switch mt-2">
|
||||
<input class="form-check-input" type="checkbox" v-model="heroForm.is_active" id="heroActive">
|
||||
<label class="form-check-label" for="heroActive">Aktif</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Görsel</label>
|
||||
<input @change="handleHeroFileUpload($event)" type="file" class="form-control">
|
||||
<div v-if="heroForm.image && typeof heroForm.image === 'string'" class="mt-2">
|
||||
<small>Mevcut Görsel:</small>
|
||||
<img :src="config.public.BASE_API_URL + heroForm.image" height="80" class="d-block mt-1 rounded">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mb-3">
|
||||
<div class="p-3 bg-light rounded border">
|
||||
<h6>Resim Optimizasyon Ayarları</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Format</label>
|
||||
<select v-model="imageSettings.format" class="form-select">
|
||||
<option value="avif">AVIF</option>
|
||||
<option value="webp">WEBP</option>
|
||||
<option value="png">PNG</option>
|
||||
<option value="jpg">JPG</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Kalite</label>
|
||||
<input v-model="imageSettings.quality" type="number" min="1" max="100" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Genişlik</label>
|
||||
<input v-model="imageSettings.width" type="number" class="form-control" placeholder="Opsiyonel">
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Yükseklik</label>
|
||||
<input v-model="imageSettings.height" type="number" class="form-control"
|
||||
placeholder="Opsiyonel">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<button type="button" class="btn btn-secondary me-2" data-bs-dismiss="modal">İptal</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Kaydet
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Setting } from '~~/types/setting';
|
||||
import type { Hero } from '~~/types/hero';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'admin'
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const { data: authData } = useAuth();
|
||||
const loading = ref(false);
|
||||
|
||||
// --- SETTINGS ---
|
||||
const settingForm = ref<Partial<Setting>>({});
|
||||
const w_logo_file = ref<File | null>(null);
|
||||
const b_logo_file = ref<File | null>(null);
|
||||
|
||||
const imageSettings = ref({
|
||||
format: 'avif',
|
||||
quality: 80,
|
||||
width: null as number | null,
|
||||
height: null as number | null
|
||||
});
|
||||
|
||||
// Fetch Settings
|
||||
const fetchSettings = async () => {
|
||||
try {
|
||||
const data = await $fetch<Setting>('/api/v1/setting', {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
});
|
||||
if (data) {
|
||||
settingForm.value = { ...data };
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Settings fetch error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileUpload = (event: Event, type: 'w_logo' | 'b_logo') => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files && target.files[0]) {
|
||||
if (type === 'w_logo') w_logo_file.value = target.files[0];
|
||||
if (type === 'b_logo') b_logo_file.value = target.files[0];
|
||||
}
|
||||
};
|
||||
|
||||
const optimizeImage = async (file: File): Promise<File> => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('format', imageSettings.value.format);
|
||||
formData.append('quality', String(imageSettings.value.quality));
|
||||
if (imageSettings.value.width) formData.append('width', String(imageSettings.value.width));
|
||||
if (imageSettings.value.height) formData.append('height', String(imageSettings.value.height));
|
||||
|
||||
const optimizedBlob = await $fetch<Blob>('/api/optimize', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
responseType: 'blob'
|
||||
});
|
||||
|
||||
const ext = imageSettings.value.format === 'jpg' ? 'jpeg' : imageSettings.value.format;
|
||||
const filename = `img-${Date.now()}-${Math.floor(Math.random() * 10000)}.${ext === 'jpeg' ? 'jpg' : ext}`;
|
||||
|
||||
const optimizedFile = new File([optimizedBlob], filename, {
|
||||
type: `image/${ext}`
|
||||
});
|
||||
|
||||
return optimizedFile;
|
||||
};
|
||||
|
||||
const updateSettings = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const formData = new FormData();
|
||||
Object.keys(settingForm.value).forEach(key => {
|
||||
const value = (settingForm.value as any)[key];
|
||||
if (value !== null && value !== undefined && key !== 'w_logo' && key !== 'b_logo' && key !== 'ID' && key !== 'CreatedAt' && key !== 'UpdatedAt' && key !== 'DeletedAt') {
|
||||
formData.append(key, String(value));
|
||||
}
|
||||
});
|
||||
|
||||
if (w_logo_file.value) {
|
||||
const optimized = await optimizeImage(w_logo_file.value);
|
||||
formData.append('w_logo', optimized);
|
||||
}
|
||||
if (b_logo_file.value) {
|
||||
const optimized = await optimizeImage(b_logo_file.value);
|
||||
formData.append('b_logo', optimized);
|
||||
}
|
||||
|
||||
formData.append('is_active', 'true');
|
||||
|
||||
let url = '/api/v1/setting';
|
||||
let method: 'POST' | 'PUT' = 'POST';
|
||||
|
||||
if (settingForm.value.ID) {
|
||||
url = `/api/v1/setting/${settingForm.value.ID}`;
|
||||
method = 'PUT';
|
||||
}
|
||||
|
||||
await $fetch(url, {
|
||||
method: method,
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
body: formData,
|
||||
headers: {
|
||||
Authorization: `Bearer ${(authData.value as any)?.accessToken}`
|
||||
}
|
||||
});
|
||||
|
||||
Swal.fire('Başarılı', 'Ayarlar güncellendi.', 'success');
|
||||
fetchSettings(); // Refresh
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Güncelleme sırasında hata oluştu.', 'error');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// --- HERO ---
|
||||
const heroes = ref<Hero[]>([]);
|
||||
const heroForm = ref<Partial<Hero>>({});
|
||||
const heroImageFile = ref<File | null>(null);
|
||||
const isEditingHero = ref(false);
|
||||
let heroModal: any = null;
|
||||
|
||||
const fetchHeroes = async () => {
|
||||
try {
|
||||
const response = await $fetch<any>('/api/v1/heroes', {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
});
|
||||
|
||||
if (response && Array.isArray(response.data)) {
|
||||
heroes.value = response.data;
|
||||
} else if (Array.isArray(response)) {
|
||||
heroes.value = response;
|
||||
} else if (response && typeof response === 'object') {
|
||||
heroes.value = [response]; // Wrap single object
|
||||
} else {
|
||||
heroes.value = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Hero fetch error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const openHeroModal = (hero: Hero | null = null) => {
|
||||
if (hero) {
|
||||
isEditingHero.value = true;
|
||||
heroForm.value = { ...hero };
|
||||
} else {
|
||||
isEditingHero.value = false;
|
||||
heroForm.value = { is_active: true };
|
||||
}
|
||||
heroImageFile.value = null;
|
||||
|
||||
// Initialize Modal
|
||||
const modalEl = document.getElementById('heroModal');
|
||||
if (modalEl) {
|
||||
// @ts-ignore
|
||||
heroModal = new bootstrap.Modal(modalEl);
|
||||
heroModal.show();
|
||||
}
|
||||
};
|
||||
|
||||
const handleHeroFileUpload = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files && target.files[0]) {
|
||||
heroImageFile.value = target.files[0];
|
||||
}
|
||||
};
|
||||
|
||||
const saveHero = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const formData = new FormData();
|
||||
Object.keys(heroForm.value).forEach(key => {
|
||||
const value = (heroForm.value as any)[key];
|
||||
if (value !== null && value !== undefined && key !== 'image' && key !== 'ID' && key !== 'CreatedAt' && key !== 'UpdatedAt' && key !== 'DeletedAt') {
|
||||
formData.append(key, String(value));
|
||||
}
|
||||
});
|
||||
|
||||
if (heroImageFile.value) {
|
||||
const optimized = await optimizeImage(heroImageFile.value);
|
||||
formData.append('image', optimized);
|
||||
}
|
||||
|
||||
// Ensure is_active sent as string 'true'/'false' if backend expects it
|
||||
// formData.set('is_active', String(heroForm.value.is_active));
|
||||
|
||||
let url = '/api/v1/hero';
|
||||
let method: 'POST' | 'PUT' = 'POST';
|
||||
|
||||
if (isEditingHero.value && heroForm.value.ID) {
|
||||
url = `/api/v1/hero/${heroForm.value.ID}`;
|
||||
method = 'PUT';
|
||||
}
|
||||
|
||||
await $fetch(url, {
|
||||
method: method,
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
body: formData,
|
||||
headers: {
|
||||
Authorization: `Bearer ${(authData.value as any)?.accessToken}`
|
||||
}
|
||||
});
|
||||
|
||||
if (heroModal) heroModal.hide();
|
||||
Swal.fire('Başarılı', `Hero ${isEditingHero.value ? 'güncellendi' : 'eklendi'}.`, 'success');
|
||||
fetchHeroes();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'İşlem başarısız.', 'error');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteHero = async (id: number) => {
|
||||
const result = await Swal.fire({
|
||||
title: 'Emin misiniz?',
|
||||
text: "Bu hero kaydını silmek istediğinize emin misiniz?",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet, Sil',
|
||||
cancelButtonText: 'İptal'
|
||||
});
|
||||
|
||||
if (result.isConfirmed) {
|
||||
try {
|
||||
await $fetch(`/api/v1/hero/${id}`, {
|
||||
method: 'DELETE',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: {
|
||||
Authorization: `Bearer ${(authData.value as any)?.accessToken}`
|
||||
}
|
||||
});
|
||||
Swal.fire('Silindi!', 'Kayıt başarıyla silindi.', 'success');
|
||||
fetchHeroes();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Silme işlemi başarısız.', 'error');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchSettings();
|
||||
fetchHeroes();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Tabs styling */
|
||||
.nav-tabs .nav-link {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link.active {
|
||||
font-weight: bold;
|
||||
color: #0d6efd;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user