Spaces:
Sleeping
Sleeping
File size: 6,497 Bytes
3c841ba | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | 'use client';
export const ACENTE_FEEDBACK_KEY = 'ajet360.acente.feedback.v1';
export const ACENTE_FEEDBACK_EVENT = 'ajet360:acente-feedback';
export type FeedbackCategory = 'Şikayet' | 'Öneri' | 'Teşekkür' | 'Teknik Sorun' | 'Sözleşme/Komisyon';
export type FeedbackStatus = 'Gönderildi' | 'AJet İncelemede' | 'Yanıtlandı' | 'Kapatıldı';
export type FeedbackReply = {
at: string;
from: 'AJet' | 'Acente';
authorName: string;
body: string;
};
export type Feedback = {
id: string;
agencyCode: string;
category: FeedbackCategory;
subject: string;
body: string;
status: FeedbackStatus;
createdAt: string;
replies: FeedbackReply[];
};
const SEED_FEEDBACKS: Feedback[] = [
{
id: 'fb-demo-001',
agencyCode: 'AJ-IST-001',
category: 'Sözleşme/Komisyon',
subject: 'Sözleşme komisyon yapısı hakkında',
body: 'Yeni dönem sözleşmesinde Q3 için komisyon dilimlerinin yeniden değerlendirilmesini talep ediyorum. Mevcut yapıda %12 komisyon hedef hacmin altında kalıyor; %14\'e çıkarılması mümkün mü?',
status: 'Yanıtlandı',
createdAt: '2026-04-18T09:30:00.000Z',
replies: [
{
at: '2026-04-19T11:00:00.000Z',
from: 'AJet',
authorName: 'Mehmet Yılmaz · Satış Müdürü',
body: 'Talebinizi inceledik. Q3 itibarıyla %14 komisyon dilimine geçişiniz için gerekli değerlendirme süreci başlatıldı. 7 iş günü içinde yeni sözleşme taslağı tarafınıza iletilecektir.',
},
{
at: '2026-04-19T14:20:00.000Z',
from: 'Acente',
authorName: 'Istanbul Jet Travel',
body: 'Hızlı dönüş için teşekkürler, taslağı bekliyoruz.',
},
],
},
{
id: 'fb-demo-002',
agencyCode: 'AJ-IST-001',
category: 'Teknik Sorun',
subject: 'Crane Pax bakiye yükleme yavaş',
body: 'Son 1 haftadır Crane Pax üzerinden bakiye yüklemesi 5–7 dakika sürüyor. Önceden anında yansıyordu. İncelenmesi mümkün mü?',
status: 'AJet İncelemede',
createdAt: '2026-04-23T08:45:00.000Z',
replies: [
{
at: '2026-04-23T10:15:00.000Z',
from: 'AJet',
authorName: 'Sistem Destek',
body: 'Geri bildiriminiz alındı. Crane Pax entegrasyon ekibimizle paylaşıldı, 24 saat içinde dönüş yapılacaktır.',
},
],
},
{
id: 'fb-demo-003',
agencyCode: 'AJ-ANK-001',
category: 'Teşekkür',
subject: 'Yeni eğitim için teşekkürler',
body: 'Geçen hafta düzenlenen PNR v2 eğitimi çok faydalıydı, ekipçe katıldık. Bu tip eğitimlerin devamını rica ediyoruz.',
status: 'Yanıtlandı',
createdAt: '2026-04-15T16:00:00.000Z',
replies: [
{
at: '2026-04-16T09:00:00.000Z',
from: 'AJet',
authorName: 'Eğitim Koordinatörü',
body: 'Geri dönüşünüz için teşekkür ederiz. Mayıs ayında Crane Pax kullanımı eğitimi planlıyoruz, davetiye e-postanız gelecek.',
},
],
},
];
function canUseStorage() {
return typeof window !== 'undefined' && Boolean(window.localStorage);
}
function readAll(): Feedback[] {
if (!canUseStorage()) return SEED_FEEDBACKS;
const raw = window.localStorage.getItem(ACENTE_FEEDBACK_KEY);
if (!raw) {
return SEED_FEEDBACKS;
}
try {
const parsed = JSON.parse(raw) as Feedback[];
if (!Array.isArray(parsed)) return SEED_FEEDBACKS;
const seedIds = new Set(SEED_FEEDBACKS.map((s) => s.id));
const userOnes = parsed.filter((f) => !seedIds.has(f.id));
return [...userOnes, ...SEED_FEEDBACKS];
} catch {
return SEED_FEEDBACKS;
}
}
function writeAll(items: Feedback[]) {
if (!canUseStorage()) return;
const seedIds = new Set(SEED_FEEDBACKS.map((s) => s.id));
const persisted = items.filter((f) => !seedIds.has(f.id));
const seedOverrides = items.filter(
(f) => seedIds.has(f.id) && hasNewReplies(f),
);
window.localStorage.setItem(
ACENTE_FEEDBACK_KEY,
JSON.stringify([...persisted, ...seedOverrides]),
);
window.dispatchEvent(new Event(ACENTE_FEEDBACK_EVENT));
}
function hasNewReplies(f: Feedback): boolean {
const seed = SEED_FEEDBACKS.find((s) => s.id === f.id);
if (!seed) return false;
return f.replies.length > seed.replies.length || f.status !== seed.status;
}
export function listFeedbacks(agencyCode: string): Feedback[] {
return readAll()
.filter((f) => f.agencyCode === agencyCode)
.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
}
export function getFeedbackById(id: string): Feedback | undefined {
return readAll().find((f) => f.id === id);
}
export type CreateFeedbackInput = {
agencyCode: string;
category: FeedbackCategory;
subject: string;
body: string;
};
export function createFeedback(input: CreateFeedbackInput): Feedback {
const now = new Date().toISOString();
const ts = now.replace(/\D/g, '').slice(0, 14);
const fb: Feedback = {
id: `fb-${ts}-${Math.random().toString(36).slice(2, 6)}`,
agencyCode: input.agencyCode,
category: input.category,
subject: input.subject,
body: input.body,
status: 'Gönderildi',
createdAt: now,
replies: [],
};
writeAll([fb, ...readAll()]);
return fb;
}
export function appendReply(id: string, reply: Omit<FeedbackReply, 'at'> & { at?: string }): Feedback | undefined {
const all = readAll();
const idx = all.findIndex((f) => f.id === id);
if (idx < 0) return undefined;
const at = reply.at ?? new Date().toISOString();
const next = { ...all[idx]!, replies: [...all[idx]!.replies, { ...reply, at }] };
if (reply.from === 'AJet') {
next.status = 'Yanıtlandı';
}
const arr = [...all];
arr[idx] = next;
writeAll(arr);
return next;
}
export function transitionStatus(id: string, status: FeedbackStatus): Feedback | undefined {
const all = readAll();
const idx = all.findIndex((f) => f.id === id);
if (idx < 0) return undefined;
const next = { ...all[idx]!, status };
const arr = [...all];
arr[idx] = next;
writeAll(arr);
return next;
}
export function simulateAjetAutoReply(id: string) {
setTimeout(() => {
appendReply(id, {
from: 'AJet',
authorName: 'AJet Acente İlişkileri',
body: 'Geri bildiriminiz alındı. Konuyla ilgili 24 saat içinde dönüş yapılacaktır. Acil durumlar için temsilcinizle iletişime geçebilirsiniz.',
});
}, 8000);
setTimeout(() => {
transitionStatus(id, 'AJet İncelemede');
}, 1500);
}
|