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);
}