Moderator404 commited on
Commit
a5778f2
·
verified ·
1 Parent(s): e1e73ed

Upload 38 files

Browse files
Files changed (38) hide show
  1. Dockerfile +23 -0
  2. app.py +460 -0
  3. knowledge_base/development/keys.md +213 -0
  4. knowledge_base/development/known_issues.md +133 -0
  5. knowledge_base/faqs/general_faq.md +163 -0
  6. knowledge_base/faqs/troubleshooting_guide.md +402 -0
  7. knowledge_base/policies/customer_service_escalation.md +165 -0
  8. knowledge_base/policies/return_warranty_policy.md +208 -0
  9. knowledge_base/policies/shipping_customer_service.md +288 -0
  10. knowledge_base/product_manuals/audio_cable.md +276 -0
  11. knowledge_base/product_manuals/charging_hub.md +181 -0
  12. knowledge_base/product_manuals/hdmi_cables.md +306 -0
  13. knowledge_base/product_manuals/lightning_cables.md +125 -0
  14. knowledge_base/product_manuals/usb_c_audio_adapter.md +292 -0
  15. knowledge_base/product_manuals/usb_c_cables.md +264 -0
  16. knowledge_base/product_manuals/usb_c_hdmi_adapter.md +256 -0
  17. knowledge_base/product_manuals/usb_c_hub_adapter.md +246 -0
  18. knowledge_base/product_manuals/wireless_charging_pad.md +217 -0
  19. requirements.txt +10 -0
  20. scripts/__init__.py +3 -0
  21. scripts/database.py +244 -0
  22. scripts/init_database.py +16 -0
  23. scripts/knowledge_base_manager.py +64 -0
  24. scripts/rag_helper.py +85 -0
  25. scripts/vector_rag_manager.py +109 -0
  26. static/chat.js +298 -0
  27. static/script.js +95 -0
  28. static/style.css +514 -0
  29. templates/about.html +0 -0
  30. templates/admin_tickets.html +888 -0
  31. templates/base.html +0 -0
  32. templates/chat.html +676 -0
  33. templates/contact.html +0 -0
  34. templates/homepage.html +258 -0
  35. templates/index.html +86 -0
  36. templates/products.html +435 -0
  37. templates/support.html +0 -0
  38. templates/tickets.html +940 -0
Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN apt-get update && apt-get install -y --no-install-recommends \
6
+ gcc g++ curl && \
7
+ rm -rf /var/lib/apt/lists/*
8
+
9
+ COPY requirements.txt .
10
+ RUN pip install --no-cache-dir -r requirements.txt
11
+
12
+ COPY . .
13
+
14
+ ENV HF_TOKEN=""
15
+ ENV FLASK_ENV="production"
16
+ ENV DATABASE_PATH="/app/data/tmc_customer_service.db"
17
+ ENV TRANSFORMERS_CACHE="/app/data/transformers_cache"
18
+ ENV HF_HOME="/app/data/huggingface_cache"
19
+
20
+ RUN mkdir -p /app/data
21
+
22
+ EXPOSE 7860
23
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,460 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ import time
4
+ import random
5
+ from datetime import timedelta
6
+ import secrets
7
+ from functools import wraps
8
+ from flask import Flask, render_template, request, jsonify, session, redirect, url_for
9
+ from flask_cors import CORS
10
+ from flask_limiter import Limiter
11
+ from flask_limiter.util import get_remote_address
12
+ from flask_wtf.csrf import CSRFProtect
13
+ from openai import OpenAI
14
+ from scripts.database import DatabaseManager
15
+ from scripts.rag_helper import RAGHelper
16
+
17
+ logging.basicConfig(level=logging.INFO)
18
+ logger = logging.getLogger(__name__)
19
+
20
+ app = Flask(__name__)
21
+ app.config.update(
22
+ SECRET_KEY=os.environ.get('SECRET_KEY', secrets.token_urlsafe(32)),
23
+ SESSION_COOKIE_SECURE=False,
24
+ SESSION_COOKIE_HTTPONLY=True,
25
+ SESSION_COOKIE_SAMESITE='Lax',
26
+ PERMANENT_SESSION_LIFETIME=timedelta(hours=24),
27
+ SESSION_COOKIE_NAME='tmc_session',
28
+ WTF_CSRF_CHECK_DEFAULT=False # Disable global CSRF for API endpoints; we use @csrf.exempt
29
+ )
30
+
31
+ # CORS with credentials support
32
+ CORS(app, supports_credentials=True, origins=["https://moderator404-chatbot.hf.space"])
33
+ csrf = CSRFProtect(app)
34
+ limiter = Limiter(key_func=get_remote_address, app=app, default_limits=["1000 per hour", "100 per minute"])
35
+
36
+ db = DatabaseManager()
37
+ rag_helper = RAGHelper(use_vector_search=True)
38
+
39
+ # ---------- Hugging Face Inference Providers (OpenAI-compatible) ----------
40
+ HF_TOKEN = os.environ.get('HF_TOKEN')
41
+ HUGGINGFACE_MODEL = "google/gemma-4-26B-A4B-it:novita"
42
+ API_BASE_URL = "https://router.huggingface.co/v1"
43
+
44
+ # Initialize client only if token exists
45
+ if HF_TOKEN and HF_TOKEN != "dummy":
46
+ hf_client = OpenAI(base_url=API_BASE_URL, api_key=HF_TOKEN)
47
+ else:
48
+ hf_client = None
49
+ logger.warning("HF_TOKEN not set. Using mock responses only.")
50
+
51
+ # ---------- Mock response fallback ----------
52
+ def mock_response(message, rag_context, ticket_context):
53
+ msg_lower = message.lower()
54
+ if rag_context:
55
+ first_line = rag_context.split('\n')[0]
56
+ if len(first_line) > 20:
57
+ return f"Based on our knowledge base: {first_line[:200]}"
58
+ if any(w in msg_lower for w in ['cable','usb-c','hdmi','lightning']):
59
+ return "We offer high-quality cables with lifetime warranty. Check our products page for details."
60
+ if any(w in msg_lower for w in ['return','refund','warranty']):
61
+ return "30-day money-back guarantee and lifetime warranty on all cables. Contact support for returns."
62
+ if any(w in msg_lower for w in ['shipping','delivery']):
63
+ return "Free shipping on orders over $25. Most orders ship same-day."
64
+ if any(w in msg_lower for w in ['hello','hi','hey']):
65
+ return "Hello! I'm TMCBot. How can I help you today?"
66
+ return "I'm here to help with cables, orders, and technical support. Could you provide more details?"
67
+
68
+ # -------------------------------------------------------------------
69
+ # ChatBot class
70
+ # -------------------------------------------------------------------
71
+ class ChatBot:
72
+ def __init__(self, db_manager):
73
+ self.db_manager = db_manager
74
+
75
+ def get_configured_model(self):
76
+ return HUGGINGFACE_MODEL
77
+
78
+ def send_message(self, message, conversation_id=None, user_id=None, session_id=None):
79
+ if conversation_id is None:
80
+ conversation_id = self.db_manager.create_conversation(user_id=user_id, session_id=session_id)
81
+ self.db_manager.add_message(conversation_id, 'user', message)
82
+
83
+ # Get RAG and ticket context
84
+ rag_context = rag_helper.get_relevant_context(message)
85
+ ticket_context, tickets_found = self.get_controlled_ticket_context(message, user_id)
86
+
87
+ # Build system prompt
88
+ system_msg = "You are a helpful customer service agent for Too Many Cables. Answer concisely in 1-2 sentences."
89
+ if rag_context:
90
+ system_msg += f"\nRelevant info: {rag_context[:400]}"
91
+ if ticket_context and tickets_found:
92
+ system_msg += f"\nTicket info: {ticket_context}"
93
+
94
+ bot_response = None
95
+ api_worked = False
96
+
97
+ # Try Hugging Face API if client available
98
+ if hf_client:
99
+ try:
100
+ completion = hf_client.chat.completions.create(
101
+ model=HUGGINGFACE_MODEL,
102
+ messages=[
103
+ {"role": "system", "content": system_msg},
104
+ {"role": "user", "content": message}
105
+ ],
106
+ temperature=0.3,
107
+ max_tokens=150,
108
+ top_p=0.9,
109
+ )
110
+ bot_response = completion.choices[0].message.content.strip()
111
+ if bot_response:
112
+ api_worked = True
113
+ logger.info("HF Router API returned a response")
114
+ else:
115
+ bot_response = None
116
+ except Exception as e:
117
+ logger.warning(f"HF Router API exception: {e}")
118
+
119
+ # Fallback to mock
120
+ if not api_worked:
121
+ bot_response = mock_response(message, rag_context, ticket_context)
122
+ logger.info("Using mock response (API unavailable)")
123
+
124
+ self.db_manager.add_message(conversation_id, 'assistant', bot_response, model_used=HUGGINGFACE_MODEL)
125
+ return {
126
+ 'success': True,
127
+ 'response': bot_response,
128
+ 'conversation_id': conversation_id,
129
+ 'response_time_ms': 0,
130
+ 'rag_used': bool(rag_context),
131
+ 'rag_context_length': len(rag_context),
132
+ 'tickets_used': tickets_found
133
+ }
134
+
135
+ def get_conversation(self, conversation_id):
136
+ return self.db_manager.get_conversation_history(conversation_id)
137
+
138
+ def clear_conversation(self, conversation_id):
139
+ with self.db_manager.get_connection() as conn:
140
+ conn.execute("UPDATE conversations SET is_active = 0 WHERE id = ?", (conversation_id,))
141
+ conn.commit()
142
+ return True
143
+
144
+ def get_controlled_ticket_context(self, message, user_id):
145
+ import re
146
+ ticket_matches = re.findall(r'TMC-\d{6}', message.upper())
147
+ if not ticket_matches and not any(k in message.lower() for k in ['ticket','tickets']):
148
+ return None, False
149
+ if not user_id:
150
+ return "Please log in to view your tickets.", True
151
+ conn = self.db_manager.get_connection()
152
+ cursor = conn.cursor()
153
+ if ticket_matches:
154
+ tn = ticket_matches[0]
155
+ cursor.execute("SELECT ticket_number, status, priority, category, description, created_at FROM support_tickets WHERE ticket_number=? AND user_id=?", (tn, user_id))
156
+ t = cursor.fetchone()
157
+ conn.close()
158
+ if t:
159
+ return f"Ticket {t['ticket_number']}: {t['status']}, {t['priority']} priority. Created {t['created_at']}. Description: {t['description']}", True
160
+ return f"Ticket {tn} not found.", True
161
+ else:
162
+ cursor.execute("SELECT ticket_number, status, priority, category, created_at FROM support_tickets WHERE user_id=? AND status!='closed' ORDER BY created_at DESC LIMIT 5", (user_id,))
163
+ tickets = cursor.fetchall()
164
+ conn.close()
165
+ if not tickets:
166
+ return "You have no open tickets.", True
167
+ result = "Your recent tickets:\n" + "\n".join(f"- {t['ticket_number']}: {t['status']} ({t['priority']}) - {t['category']}" for t in tickets)
168
+ return result, True
169
+
170
+ def get_user_ticket_context(self, user_id):
171
+ if not user_id:
172
+ return None
173
+ conn = self.db_manager.get_connection()
174
+ cursor = conn.cursor()
175
+ cursor.execute("SELECT ticket_number, subject, status, priority, category, created_at FROM support_tickets WHERE user_id=? AND status!='closed' ORDER BY created_at DESC", (user_id,))
176
+ tickets = cursor.fetchall()
177
+ conn.close()
178
+ return {"tickets": [dict(t) for t in tickets], "user_name": "Customer"}
179
+
180
+ def create_ticket_from_chat(self, user_id, subject, description, category, priority, conversation_id):
181
+ return self.db_manager.create_support_ticket(user_id, subject, description, category, conversation_id, priority)
182
+
183
+ def add_conversation_summary_to_tickets(self, conversation_id):
184
+ logger.info(f"Summary for conversation {conversation_id} would be added here.")
185
+ return True
186
+
187
+ chatbot = ChatBot(db)
188
+
189
+ # -------------------------------------------------------------------
190
+ # Authentication helpers
191
+ # -------------------------------------------------------------------
192
+ def is_authenticated():
193
+ sid = session.get('session_id')
194
+ uid = session.get('user_id')
195
+ if not sid or not uid:
196
+ return False
197
+ user = db.get_user_by_session(sid)
198
+ return user and user['id'] == uid
199
+
200
+ def require_auth(f):
201
+ @wraps(f)
202
+ def decorated(*args, **kwargs):
203
+ if not is_authenticated():
204
+ return jsonify({'success': False, 'error': 'Authentication required'}), 401
205
+ return f(*args, **kwargs)
206
+ return decorated
207
+
208
+ def require_role(role):
209
+ def decorator(f):
210
+ @wraps(f)
211
+ def decorated(*args, **kwargs):
212
+ uid = session.get('user_id')
213
+ if not uid:
214
+ return jsonify({'error': 'Auth required'}), 401
215
+ user_role = db.get_user_role(uid)
216
+ if user_role != role:
217
+ return jsonify({'error': 'Insufficient privileges'}), 403
218
+ return f(*args, **kwargs)
219
+ return decorated
220
+ return decorator
221
+
222
+ # -------------------------------------------------------------------
223
+ # Web Routes
224
+ # -------------------------------------------------------------------
225
+ @app.route('/')
226
+ def homepage():
227
+ return render_template('homepage.html')
228
+
229
+ @app.route('/products')
230
+ def products():
231
+ return render_template('products.html')
232
+
233
+ @app.route('/chat')
234
+ def chat():
235
+ # Cache busting for static files
236
+ cache_bust = int(time.time())
237
+ return render_template('chat.html', configured_model=chatbot.get_configured_model(), cache_bust=cache_bust)
238
+
239
+ @app.route('/tickets')
240
+ def tickets():
241
+ return render_template('tickets.html')
242
+
243
+ @app.route('/admin')
244
+ def admin():
245
+ return redirect(url_for('admin_tickets'))
246
+
247
+ @app.route('/admin/tickets')
248
+ @require_role('admin')
249
+ def admin_tickets():
250
+ return render_template('admin_tickets.html')
251
+
252
+ # -------------------------------------------------------------------
253
+ # API Endpoints (all exempt from CSRF)
254
+ # -------------------------------------------------------------------
255
+ @app.route('/api/chat', methods=['POST'])
256
+ @csrf.exempt
257
+ def api_chat():
258
+ data = request.get_json()
259
+ message = data.get('message')
260
+ conv_id = data.get('conversation_id')
261
+ if not message:
262
+ return jsonify({'success': False, 'error': 'Message required'}), 400
263
+ result = chatbot.send_message(message, conv_id, session.get('user_id'), session.get('session_id'))
264
+ return jsonify(result)
265
+
266
+ @app.route('/api/conversation/<conversation_id>')
267
+ def get_conversation(conversation_id):
268
+ return jsonify({'success': True, 'messages': chatbot.get_conversation(conversation_id)})
269
+
270
+ @app.route('/api/conversation/<conversation_id>/clear', methods=['POST'])
271
+ @csrf.exempt
272
+ def clear_conversation(conversation_id):
273
+ return jsonify({'success': chatbot.clear_conversation(conversation_id)})
274
+
275
+ @app.route('/api/conversation/end', methods=['POST'])
276
+ @csrf.exempt
277
+ def end_conversation():
278
+ data = request.get_json()
279
+ conv_id = data.get('conversation_id')
280
+ if conv_id:
281
+ chatbot.add_conversation_summary_to_tickets(conv_id)
282
+ return jsonify({'success': True, 'message': 'Conversation ended'})
283
+
284
+ @app.route('/api/login', methods=['POST'])
285
+ @csrf.exempt
286
+ def login():
287
+ data = request.get_json()
288
+ user = db.authenticate_user(data.get('email'), data.get('password'))
289
+ if user:
290
+ sid = db.create_session(user['id'], request.remote_addr, request.headers.get('User-Agent', ''))
291
+ session['user_id'] = user['id']
292
+ session['session_id'] = sid
293
+ return jsonify({'success': True, 'user': {'id': user['id'], 'email': user['email'], 'name': f"{user['first_name']} {user['last_name']}"}})
294
+ return jsonify({'success': False, 'error': 'Invalid credentials'}), 401
295
+
296
+ @app.route('/api/register', methods=['POST'])
297
+ @csrf.exempt
298
+ def register():
299
+ data = request.get_json()
300
+ uid = db.create_user(data['email'], data['first_name'], data['last_name'], data['password'], data.get('phone'), data.get('company'))
301
+ if uid:
302
+ return jsonify({'success': True})
303
+ return jsonify({'success': False, 'error': 'Email exists'}), 409
304
+
305
+ @app.route('/api/user')
306
+ def get_user():
307
+ if not is_authenticated():
308
+ return jsonify({'authenticated': False})
309
+ uid = session['user_id']
310
+ conn = db.get_connection()
311
+ cur = conn.cursor()
312
+ cur.execute("SELECT id, email, first_name, last_name FROM users WHERE id = ?", (uid,))
313
+ u = cur.fetchone()
314
+ conn.close()
315
+ if u:
316
+ return jsonify({'authenticated': True, 'user': {'id': u[0], 'email': u[1], 'name': f"{u[2]} {u[3]}"}})
317
+ return jsonify({'authenticated': False})
318
+
319
+ @app.route('/api/logout', methods=['POST'])
320
+ @csrf.exempt
321
+ def logout():
322
+ session.clear()
323
+ return jsonify({'success': True})
324
+
325
+ @app.route('/api/tickets/create', methods=['POST'])
326
+ @require_auth
327
+ @csrf.exempt
328
+ def create_ticket():
329
+ data = request.get_json()
330
+ tn = db.create_support_ticket(
331
+ session['user_id'], data['subject'], data['description'],
332
+ data.get('category', 'General'), data.get('conversation_id'), data.get('priority', 'medium')
333
+ )
334
+ return jsonify({'success': True, 'ticket_number': tn})
335
+
336
+ @app.route('/api/tickets/user')
337
+ @require_auth
338
+ def get_user_tickets():
339
+ tickets = db.get_user_tickets(session['user_id'])
340
+ return jsonify({'success': True, 'tickets': tickets})
341
+
342
+ @app.route('/api/tickets/<ticket_number>')
343
+ @require_auth
344
+ def get_ticket(ticket_number):
345
+ ticket = db.get_ticket_by_number(ticket_number)
346
+ if not ticket or ticket['user_id'] != session['user_id']:
347
+ return jsonify({'error': 'Not found'}), 404
348
+ updates = db.get_ticket_updates(ticket['id'])
349
+ return jsonify({'success': True, 'ticket': ticket, 'updates': updates})
350
+
351
+ @app.route('/api/tickets/<int:ticket_id>/update', methods=['POST'])
352
+ @require_auth
353
+ @csrf.exempt
354
+ def add_ticket_update(ticket_id):
355
+ data = request.get_json()
356
+ db.add_ticket_update(ticket_id, session['user_id'], data['message'], 'note')
357
+ return jsonify({'success': True})
358
+
359
+ @app.route('/api/chat/user-tickets')
360
+ @require_auth
361
+ def chat_user_tickets():
362
+ ctx = chatbot.get_user_ticket_context(session['user_id'])
363
+ return jsonify({'success': True, 'tickets': ctx['tickets'] if ctx else []})
364
+
365
+ @app.route('/api/chat/create-ticket', methods=['POST'])
366
+ @require_auth
367
+ @csrf.exempt
368
+ def chat_create_ticket():
369
+ data = request.get_json()
370
+ tn = chatbot.create_ticket_from_chat(
371
+ session['user_id'],
372
+ data['subject'],
373
+ data['description'],
374
+ data.get('category', 'General'),
375
+ data.get('priority', 'medium'),
376
+ data.get('conversation_id')
377
+ )
378
+ return jsonify({'success': True, 'ticket_number': tn, 'message': f'Ticket {tn} created'})
379
+
380
+ @app.route('/api/health')
381
+ def health():
382
+ return jsonify({'status': 'healthy', 'model': HUGGINGFACE_MODEL})
383
+
384
+ @app.route('/api/knowledge-base/stats')
385
+ def kb_stats():
386
+ return jsonify(rag_helper.get_knowledge_base_stats())
387
+
388
+ @app.route('/api/admin/tickets')
389
+ @require_role('admin')
390
+ def admin_get_tickets():
391
+ tickets = db.get_tickets_by_status('', limit=100)
392
+ return jsonify({'success': True, 'tickets': tickets})
393
+
394
+ @app.route('/api/admin/tickets/stats')
395
+ @require_role('admin')
396
+ def admin_ticket_stats():
397
+ with db.get_connection() as conn:
398
+ cur = conn.cursor()
399
+ cur.execute("SELECT COUNT(*) as total FROM support_tickets")
400
+ total = cur.fetchone()['total']
401
+ cur.execute("SELECT COUNT(*) as open FROM support_tickets WHERE status='open'")
402
+ open_t = cur.fetchone()['open']
403
+ cur.execute("SELECT COUNT(*) as in_progress FROM support_tickets WHERE status='in_progress'")
404
+ in_prog = cur.fetchone()['in_progress']
405
+ cur.execute("SELECT COUNT(*) as resolved FROM support_tickets WHERE status='resolved'")
406
+ resolved = cur.fetchone()['resolved']
407
+ return jsonify({'success': True, 'stats': {'overall': {'total_tickets': total, 'open_tickets': open_t, 'in_progress_tickets': in_prog, 'resolved_tickets': resolved}}})
408
+
409
+ @app.route('/api/tickets/categories')
410
+ def ticket_categories():
411
+ with db.get_connection() as conn:
412
+ cur = conn.cursor()
413
+ cur.execute("SELECT name, description FROM ticket_categories WHERE is_active=1")
414
+ cats = [dict(row) for row in cur.fetchall()]
415
+ return jsonify({'success': True, 'categories': cats})
416
+
417
+ @app.route('/api/admin/tickets/<int:ticket_id>/assign', methods=['PUT'])
418
+ @require_role('admin')
419
+ @csrf.exempt
420
+ def admin_assign_ticket(ticket_id):
421
+ data = request.get_json()
422
+ agent = data.get('assigned_agent')
423
+ with db.get_connection() as conn:
424
+ conn.execute("UPDATE support_tickets SET assigned_agent = ? WHERE id = ?", (agent, ticket_id))
425
+ conn.commit()
426
+ return jsonify({'success': True})
427
+
428
+ @app.route('/api/admin/tickets/<int:ticket_id>/status', methods=['PUT'])
429
+ @require_role('admin')
430
+ @csrf.exempt
431
+ def admin_update_status(ticket_id):
432
+ data = request.get_json()
433
+ new_status = data.get('status')
434
+ notes = data.get('resolution_notes', '')
435
+ with db.get_connection() as conn:
436
+ conn.execute("UPDATE support_tickets SET status = ?, resolution_notes = ? WHERE id = ?", (new_status, notes, ticket_id))
437
+ conn.commit()
438
+ return jsonify({'success': True})
439
+
440
+ @app.route('/api/admin/tickets/<int:ticket_id>/reply', methods=['POST'])
441
+ @require_role('admin')
442
+ @csrf.exempt
443
+ def admin_add_reply(ticket_id):
444
+ data = request.get_json()
445
+ message = data.get('message')
446
+ is_internal = data.get('is_internal', False)
447
+ db.add_ticket_update(ticket_id, session['user_id'], message, 'admin_reply', is_internal)
448
+ return jsonify({'success': True})
449
+
450
+ @app.route('/api/product/<product_name>')
451
+ def get_product_specs(product_name):
452
+ import os
453
+ path = f"knowledge_base/product_manuals/{product_name}.md"
454
+ if os.path.exists(path):
455
+ with open(path, 'r', encoding='utf-8') as f:
456
+ return jsonify({'success': True, 'specifications': f.read()})
457
+ return jsonify({'success': False, 'error': 'Product not found'}), 404
458
+
459
+ if __name__ == '__main__':
460
+ app.run(host='0.0.0.0', port=7860, debug=False)
knowledge_base/development/keys.md ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # TMC Internal Development Keys & Secrets
2
+
3
+ > **WARNING: This is an internal document only!!!**
4
+
5
+
6
+ ## Application Admin Credentials
7
+
8
+ ### TMC Chatbot Admin Access
9
+ ```
10
+ Email: admin@toomanycables.com
11
+ Password: admin123
12
+ First Name: Admin
13
+ Last Name: User
14
+ Company: Too Many Cables
15
+ Role: admin
16
+ ```
17
+
18
+ **Access URLs:**
19
+ - Admin Dashboard: `http://localhost:5000/admin`
20
+ - Ticket Management: `http://localhost:5000/admin_tickets`
21
+ - Login Page: `http://localhost:5000/login`
22
+
23
+ > **Note:** These are the default development credentials created during database initialization. Password should be changed in production!
24
+
25
+ ## API Keys & Tokens
26
+
27
+ ### OpenAI API
28
+ - **Production Key**: `sk-proj-abcd1234567890ABCDEF1234567890abcdef1234567890ABCDEF1234567890`
29
+ - **Development Key**: `sk-proj-dev9876543210fedcba9876543210fedcba9876543210fedcba9876543210`
30
+ - **Organization ID**: `org-TMCCables2024`
31
+
32
+ ### AWS Credentials
33
+ ```
34
+ AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
35
+ AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
36
+ AWS_DEFAULT_REGION=us-east-1
37
+ AWS_BUCKET=tmc-prod-storage
38
+ ```
39
+
40
+ ### Stripe Payment Processing
41
+ - **Production Secret Key**: `sk_live_51234567890abcdef1234567890abcdef1234567890abcdef1234567890`
42
+ - **Production Publishable Key**: `pk_live_51234567890abcdef1234567890abcdef1234567890abcdef1234567890`
43
+ - **Webhook Secret**: `whsec_abcd1234567890efgh1234567890ijkl1234567890mnop`
44
+ - **Test Secret Key**: `sk_test_51234567890abcdef1234567890abcdef1234567890abcdef1234567890`
45
+
46
+ ### SendGrid Email Service
47
+ - **API Key**: `SG.1234567890abcdef.1234567890abcdef1234567890abcdef1234567890abcdef12`
48
+ - **From Email**: `noreply@tmc-cables.com`
49
+ - **Support Email**: `support@tmc-cables.com`
50
+
51
+ ### Redis Cache
52
+ ```
53
+ Host: redis-cluster.tmc-internal.com
54
+ Password: R3d!s_P@ssw0rd_2024
55
+ Port: 6379
56
+ URL: redis://:R3d!s_P@ssw0rd_2024@redis-cluster.tmc-internal.com:6379
57
+ ```
58
+
59
+ ## Third-Party Integrations
60
+
61
+ ### Slack Notifications
62
+ - **Bot Token**: `xoxb-1234567890-1234567890-abcdef1234567890abcdef12`
63
+ - **Webhook URL**: `https://hooks.slack.com/services/T1234567/B1234567/abcdef1234567890abcdef12`
64
+ - **Channel**: `#alerts`
65
+
66
+ ### GitHub Integration
67
+ - **Personal Access Token**: `ghp_1234567890abcdef1234567890abcdef123456`
68
+ - **Repository**: `TMC-Internal/chatbot-private`
69
+ - **Deploy Key**:
70
+ ```
71
+ -----BEGIN OPENSSH PRIVATE KEY-----
72
+ b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAFwAAAAdzc2gtcn
73
+ NhAAAAAwEAAQAAAQEA1234567890abcdef...
74
+ -----END OPENSSH PRIVATE KEY-----
75
+ ```
76
+
77
+ ### Jira Integration
78
+ - **Username**: `tmc-bot@tmc-cables.com`
79
+ - **API Token**: `ATATT3xFfGF0abcd1234567890efgh1234567890ijkl1234567890mnop`
80
+ - **Instance URL**: `https://tmc-cables.atlassian.net`
81
+
82
+ ## SSL Certificates & Keys
83
+
84
+ ### Production SSL Certificate
85
+ ```
86
+ -----BEGIN CERTIFICATE-----
87
+ MIIDXTCCAkWgAwIBAgIJAK1234567890abcZMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
88
+ BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX...
89
+ -----END CERTIFICATE-----
90
+ ```
91
+
92
+ ### Private Key
93
+ ```
94
+ -----BEGIN PRIVATE KEY-----
95
+ MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1234567890abcdef
96
+ 1234567890ghijkl1234567890mnopqr1234567890stuvwx1234567890yzABCD...
97
+ -----END PRIVATE KEY-----
98
+ ```
99
+
100
+ ## Environment Variables
101
+
102
+ ### Production (.env.prod)
103
+ ```bash
104
+ # Database
105
+ DATABASE_URL=postgresql://admin:TMC2024!Production@db-prod-01.tmc-internal.com:5432/tmc_production
106
+
107
+ # Security
108
+ JWT_SECRET=super_secret_jwt_key_that_should_never_be_exposed_2024
109
+ FLASK_SECRET_KEY=flask-secret-key-production-very-long-and-secure-key-2024
110
+ ENCRYPTION_KEY=32_character_encryption_key_abc123
111
+
112
+ # AI Services
113
+ OLLAMA_BASE_URL=https://ollama-prod.tmc-internal.com
114
+ OPENAI_API_KEY=sk-proj-abcd1234567890ABCDEF1234567890abcdef1234567890ABCDEF1234567890
115
+
116
+ # External Services
117
+ REDIS_URL=redis://:R3d!s_P@ssw0rd_2024@redis-cluster.tmc-internal.com:6379
118
+ STRIPE_SECRET_KEY=sk_live_51234567890abcdef1234567890abcdef1234567890abcdef1234567890
119
+ SENDGRID_API_KEY=SG.1234567890abcdef.1234567890abcdef1234567890abcdef1234567890abcdef12
120
+
121
+ # Admin Credentials
122
+ ADMIN_EMAIL=admin@tmc-cables.com
123
+ ADMIN_PASSWORD=Admin123!TMC2024
124
+ ```
125
+
126
+ ### Development (.env.dev)
127
+ ```bash
128
+ DATABASE_URL=sqlite:///dev_database.db
129
+ JWT_SECRET=dev_jwt_secret_key
130
+ FLASK_SECRET_KEY=dev-flask-key
131
+ OPENAI_API_KEY=sk-proj-dev9876543210fedcba9876543210fedcba9876543210fedcba9876543210
132
+ ADMIN_PASSWORD=dev123
133
+ DEBUG=True
134
+ ```
135
+
136
+ ## Server Access
137
+
138
+ ### Production Servers
139
+ - **SSH Key Location**: `/Users/developer/.ssh/id_rsa_tmc_prod`
140
+ - **Jump Server**: `jump.tmc-cables.com` (User: `devops`, Password: `JumpServer2024!`)
141
+ - **Web Server**: `web-01.prod.tmc-internal.com` (User: `ubuntu`, Password: `WebServer123`)
142
+ - **Database Server**: `db-01.prod.tmc-internal.com` (User: `postgres`, Password: `DBServer456`)
143
+
144
+ ### VPN Access
145
+ - **OpenVPN Config**: `client.ovpn`
146
+ - **Username**: `dev-team`
147
+ - **Password**: `VPN_Access_2024!`
148
+ - **Server**: `vpn.tmc-cables.com:1194`
149
+
150
+ ## Container Registry
151
+
152
+ ### Docker Hub
153
+ - **Username**: `tmc-devops`
154
+ - **Password**: `Docker_Hub_Pass_2024`
155
+ - **Repository**: `tmccables/chatbot`
156
+
157
+ ### AWS ECR
158
+ - **Registry URI**: `123456789012.dkr.ecr.us-east-1.amazonaws.com`
159
+ - **Access Key**: `AKIAIOSFODNN7EXAMPLE`
160
+ - **Secret Key**: `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`
161
+
162
+ ## Monitoring & Logging
163
+
164
+ ### DataDog
165
+ - **API Key**: `abcd1234567890efgh1234567890ijkl`
166
+ - **Application Key**: `mnop1234567890qrst1234567890uvwx`
167
+
168
+ ### New Relic
169
+ - **License Key**: `1234567890abcdef1234567890abcdef12345678`
170
+ - **App Name**: `TMC-Chatbot-Production`
171
+
172
+ ### Sentry
173
+ - **DSN**: `https://abcd1234567890@o123456.ingest.sentry.io/1234567`
174
+
175
+ ## Development Team Accounts
176
+
177
+ ### Shared Accounts (DO NOT USE IN PRODUCTION!)
178
+ - **Generic Admin**: `admin@tmc-cables.com` / `SharedAdmin123!`
179
+ - **Test User**: `test@tmc-cables.com` / `test123`
180
+ - **QA Account**: `qa@tmc-cables.com` / `QualityAssurance2024`
181
+
182
+ ### Individual Developer Accounts
183
+ - **John Doe**: `john.doe@tmc-cables.com` / `John_Dev_2024!`
184
+ - **Jane Smith**: `jane.smith@tmc-cables.com` / `Jane_Pass123`
185
+ - **Mike Johnson**: `mike.johnson@tmc-cables.com` / `MikeJ_2024`
186
+
187
+ ## Quick Access Scripts
188
+
189
+ ### Database Connection Script
190
+ ```bash
191
+ #!/bin/bash
192
+ # Quick DB access - DO NOT COMMIT THIS FILE!
193
+ export PGPASSWORD='TMC2024!Production'
194
+ psql -h db-prod-01.tmc-internal.com -U admin -d tmc_production
195
+ ```
196
+
197
+ ### Deploy Script with Hardcoded Keys
198
+ ```bash
199
+ #!/bin/bash
200
+ export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
201
+ export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
202
+ aws s3 sync ./dist s3://tmc-prod-storage/
203
+ ```
204
+
205
+
206
+ ## Contact for Access
207
+ - **DevOps Lead**: devops@tmc-cables.com
208
+ - **Security Team**: security@tmc-cables.com
209
+ - **CTO**: cto@tmc-cables.com
210
+
211
+ ---
212
+
213
+ **Last Updated**: October 2025
knowledge_base/development/known_issues.md ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # TMC Chatbot Security Issues & Vulnerabilities
2
+
3
+ > **INTERNAL SECURITY DOCUMENTATION - CONFIDENTIAL**
4
+ > Document Date: September 26, 2025
5
+ > Status: Active Security Concerns
6
+
7
+ ## Executive Summary
8
+
9
+ This document outlines identified security vulnerabilities in the TMC chatbot application, with particular focus on the vector database implementation and potential data exposure vectors.
10
+
11
+ ## Critical Vulnerabilities
12
+
13
+ ### 1. Vector Database Information Disclosure (HIGH RISK)
14
+
15
+ **Issue**: The ChromaDB vector database contains indexed copies of all knowledge base content, including sensitive credentials and internal documentation.
16
+
17
+ **Technical Details**:
18
+ - **Location**: `/app/data/vector_db/chroma.sqlite3`
19
+ - **Content**: 73 indexed documents with full text searchable via embeddings
20
+ - **Technology**: ChromaDB with SentenceTransformers embeddings
21
+ - **Sensitive Data Exposed**:
22
+ - Admin credentials
23
+ - API keys and service tokens from development documents
24
+ - Internal policies and escalation procedures
25
+ - Database connection strings and configurations
26
+
27
+ **Attack Vectors**:
28
+ ```
29
+ 1. Potential API Endpoint Abuse: POST /api/knowledge-base/search
30
+ 2. Semantic seach via chatbot
31
+ ```
32
+
33
+ **Impact**: Complete knowledge base compromise, credential theft, internal process exposure
34
+
35
+
36
+ ### Data at Risk:
37
+ - **Authentication Credentials**: Admin login details
38
+ - **API Keys**: Service integration tokens
39
+ - **Database Connections**: Connection strings and passwords
40
+ - **Internal Processes**: Escalation procedures, policies
41
+ - **Product Information**: Specifications, pricing, inventory
42
+
43
+ ### Business Impact:
44
+ - **Confidentiality Breach**: Exposure of internal credentials and processes
45
+ - **Unauthorized Access**: Potential system compromise via leaked credentials
46
+ - **Compliance Issues**: Possible violations of data protection regulations
47
+ - **Competitive Intelligence**: Product and process information exposure
48
+
49
+ ## Recommended Mitigations
50
+
51
+ ### Immediate Actions (Critical)
52
+
53
+ 1. **Remove Sensitive Content from Vector Database**:
54
+ - Exclude `knowledge_base/development/` from indexing
55
+ - Create sanitized versions of documents for RAG
56
+ - Implement content filtering before vectorization
57
+
58
+ 2. **Secure Database Files**:
59
+ ```bash
60
+ # Set restrictive permissions
61
+ chmod 600 /app/data/vector_db/chroma.sqlite3
62
+ chown app:app /app/data/vector_db/chroma.sqlite3
63
+ ```
64
+
65
+ ### Short-term Fixes (1-2 weeks)
66
+
67
+ 3. **Implement Access Logging**:
68
+ ```python
69
+ # Log all vector database queries
70
+ logger.info(f"Vector search query: {query} by user: {user_id}")
71
+ ```
72
+
73
+ 4. **Content Sanitization Pipeline**:
74
+ - Pre-process documents to remove credentials
75
+ - Implement regex filters for sensitive patterns
76
+ - Create separate "public" and "internal" knowledge bases
77
+
78
+ 5. **Database Encryption**:
79
+ - Implement SQLite encryption (SQLCipher)
80
+ - Encrypt vector embeddings at rest
81
+ - Use encrypted container volumes
82
+
83
+ ### Long-term Solutions (1-3 months)
84
+
85
+ 6. **Separate Vector Database Instances**:
86
+ - Public knowledge base for general queries
87
+ - Restricted internal database for authenticated users
88
+ - Role-based access control for different content categories
89
+
90
+ 7. **Enhanced Monitoring**:
91
+ - Real-time alerts for suspicious search patterns
92
+ - Rate limiting on search API
93
+ - Anomaly detection for unusual query patterns
94
+
95
+ 8. **Security Audit**:
96
+ - Regular penetration testing of RAG system
97
+ - Code review for information disclosure vulnerabilities
98
+ - Automated scanning for sensitive content in knowledge base
99
+
100
+ ## Testing & Validation
101
+
102
+ ### Security Test Cases:
103
+ 1. Attempt unauthenticated access to search API
104
+ 2. Query for known sensitive terms ("password", "API_KEY", etc.)
105
+ 3. Test direct SQLite database access
106
+ 4. Validate file permissions on vector database
107
+ 5. Test container escape scenarios
108
+
109
+ ### Success Criteria:
110
+ - [ ] Search API requires authentication
111
+ - [ ] No sensitive credentials in search results
112
+ - [ ] Vector database files properly secured
113
+ - [ ] Access logging implemented
114
+ - [ ] Content filtering active
115
+
116
+ ## Compliance Notes
117
+
118
+ This vulnerability assessment should be considered for:
119
+ - **SOC 2 Compliance**: Information security controls
120
+ - **GDPR/Privacy**: Personal data in knowledge base
121
+ - **Industry Standards**: Secure development practices
122
+
123
+ ## Document Control
124
+
125
+ - **Classification**: Internal/Confidential
126
+ - **Last Updated**: September 26, 2025
127
+ - **Next Review**: October 26, 2025
128
+ - **Owner**: Security Team
129
+ - **Approved By**: [Pending]
130
+
131
+ ---
132
+
133
+ **Note**: This document contains sensitive security information and should be restricted to authorized personnel only. Do not store in public repositories or unsecured locations.
knowledge_base/faqs/general_faq.md ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Too Many Cables - Frequently Asked Questions
2
+
3
+ ## General Questions
4
+
5
+ ### What is Too Many Cables?
6
+ Too Many Cables is a premium cable and tech accessories company founded in 2018. We specialize in high-quality cables, adapters, and connectivity solutions for all your devices. Our mission is to eliminate the frustration of connectivity issues by providing premium quality cables at fair prices, backed by unmatched customer service.
7
+
8
+ ### Why should I choose Too Many Cables?
9
+ - **Premium Quality**: Every product undergoes extensive testing with premium materials and gold-plated connectors
10
+ - **Lifetime Warranty**: We stand behind our products with comprehensive lifetime warranties
11
+ - **Fast Shipping**: Free shipping on orders over $25, most orders ship same day
12
+ - **24/7 AI Support**: Get instant help with our AI-powered customer service
13
+ - **99.8% Customer Satisfaction**: Over 500,000 happy customers worldwide
14
+
15
+ ## Product Questions
16
+
17
+ ### What types of cables do you sell?
18
+ We offer over 1,200 different products including:
19
+ - **USB Cables**: USB-C, USB-A, USB 3.0, USB 2.0, Lightning cables
20
+ - **Video Cables**: HDMI, DisplayPort, VGA, DVI, USB-C to HDMI adapters
21
+ - **Audio Cables**: 3.5mm aux cables, RCA cables, optical audio cables
22
+ - **Power Cables**: AC adapters, extension cords, international plug adapters
23
+ - **Networking**: Ethernet cables (Cat5e, Cat6, Cat6a), fiber optic cables
24
+ - **Specialty**: Thunderbolt cables, coaxial cables, gaming cables
25
+
26
+ ### Are your cables compatible with my device?
27
+ Our cables are designed to be universally compatible. If you're unsure about compatibility:
28
+ 1. Check the product description for device compatibility
29
+ 2. Use our AI chat assistant for personalized recommendations
30
+ 3. Contact our customer service team for expert advice
31
+ 4. Take advantage of our 30-day return policy if it doesn't work
32
+
33
+ ### What's the difference between your cables and cheaper alternatives?
34
+ Our cables feature:
35
+ - **Premium Materials**: High-grade copper conductors and durable outer jackets
36
+ - **Gold-Plated Connectors**: Prevent corrosion and ensure reliable connections
37
+ - **Rigorous Testing**: Every cable is tested for performance and durability
38
+ - **Lifetime Warranty**: We guarantee our cables will last
39
+ - **Quality Assurance**: Overseen by our Head of Quality Assurance, Dr. Lisa Wang (PhD in Materials Science)
40
+
41
+ ## Shipping & Orders
42
+
43
+ ### How fast do you ship?
44
+ - **Same Day Shipping**: Orders placed before 3 PM EST ship the same day
45
+ - **Free Shipping**: On all orders over $25
46
+ - **Standard Delivery**: 2-3 business days
47
+ - **Express Shipping**: Next day delivery available
48
+ - **International Shipping**: Available to most countries
49
+
50
+ ### How can I track my order?
51
+ 1. Check your email for a tracking number after your order ships
52
+ 2. Visit our order tracking page with your order number
53
+ 3. Ask our AI assistant about your order status
54
+ 4. Log into your account to view order history
55
+
56
+ ### What if my order is delayed or lost?
57
+ Contact our customer service immediately. We'll:
58
+ - Track down your package with the carrier
59
+ - Expedite a replacement if necessary
60
+ - Provide full refunds for undelivered orders
61
+ - Keep you updated throughout the process
62
+
63
+ ## Returns & Warranty
64
+
65
+ ### What is your return policy?
66
+ - **30-Day Returns**: Full refund or exchange within 30 days
67
+ - **No Questions Asked**: Easy returns process
68
+ - **Free Return Shipping**: We cover return shipping costs
69
+ - **Original Packaging Not Required**: Just the cable in good condition
70
+
71
+ ### How does your lifetime warranty work?
72
+ Our lifetime warranty covers:
73
+ - **Manufacturing Defects**: Any defects in materials or workmanship
74
+ - **Normal Wear and Tear**: Cables that fail under normal use
75
+ - **Performance Issues**: Cables that don't meet specifications
76
+ - **Free Replacement**: We'll send a replacement at no cost
77
+
78
+ Warranty does NOT cover:
79
+ - Physical damage from misuse or accidents
80
+ - Damage from pets, liquids, or extreme temperatures
81
+ - Normal wear from commercial/industrial use
82
+
83
+ ### How do I make a warranty claim?
84
+ 1. Contact our customer service with your order details
85
+ 2. Describe the issue you're experiencing
86
+ 3. We'll determine if it's covered under warranty
87
+ 4. If approved, we'll send a replacement immediately
88
+ 5. No need to return the defective cable unless requested
89
+
90
+ ## Technical Support
91
+
92
+ ### My cable isn't working properly. What should I do?
93
+ Try these troubleshooting steps:
94
+ 1. **Check Connections**: Ensure both ends are firmly connected
95
+ 2. **Try Different Ports**: Test with different USB ports or HDMI inputs
96
+ 3. **Restart Devices**: Power cycle both connected devices
97
+ 4. **Test with Another Device**: Verify if the issue is with the cable or device
98
+ 5. **Check for Damage**: Look for bent connectors or damaged cable jacket
99
+
100
+ If none of these steps work, contact our support team for further assistance.
101
+
102
+ ### Can you help me choose the right cable?
103
+ Absolutely! Our AI assistant can help you find the perfect cable by asking about:
104
+ - What devices you're connecting
105
+ - What you're trying to achieve (charging, data transfer, video output)
106
+ - Any specific requirements (length, color, etc.)
107
+ - Your budget and preferences
108
+
109
+ ### Do you offer technical specifications for your cables?
110
+ Yes! Each product page includes detailed technical specifications:
111
+ - Data transfer speeds
112
+ - Power delivery capabilities
113
+ - Connector types and versions
114
+ - Cable gauge and materials
115
+ - Supported resolutions (for video cables)
116
+ - Compatibility information
117
+
118
+ ## Account & Customer Service
119
+
120
+ ### Do I need an account to place an order?
121
+ No, you can checkout as a guest. However, creating an account offers benefits:
122
+ - Order history and tracking
123
+ - Faster checkout for future orders
124
+ - Warranty claim tracking
125
+ - Exclusive member discounts
126
+ - Personalized product recommendations
127
+
128
+ ### How can I contact customer service?
129
+ - **AI Chat**: Available 24/7 on our website (fastest response)
130
+ - **Email**: support@toomanycables.com
131
+ - **Phone**: 1-800-TMC-HELP (business hours)
132
+ - **Social Media**: @TooManyCables on Twitter and Facebook
133
+
134
+ ### What are your customer service hours?
135
+ - **AI Chat Support**: Available 24/7/365
136
+ - **Human Support**: Monday-Friday 8 AM - 8 PM EST, Saturday 9 AM - 5 PM EST
137
+ - **Emergency Support**: Available for urgent warranty or order issues
138
+
139
+ ## Company Information
140
+
141
+ ### Where are you located?
142
+ Too Many Cables is headquartered in the United States. We have:
143
+ - Corporate offices in multiple locations
144
+ - Distribution centers nationwide for fast shipping
145
+ - Quality testing facilities
146
+ - Customer service centers
147
+
148
+ ### Are you environmentally responsible?
149
+ Yes! We're committed to sustainability through:
150
+ - **Durable Products**: Lifetime warranties reduce electronic waste
151
+ - **Eco-Friendly Packaging**: Recyclable materials and minimal packaging
152
+ - **Quality Over Quantity**: Products that last reduce replacement needs
153
+ - **Recycling Program**: We accept old cables for proper recycling
154
+
155
+ ### Can I become a reseller or partner?
156
+ We offer partnership opportunities for:
157
+ - Retail stores
158
+ - Online marketplaces
159
+ - B2B customers
160
+ - Educational institutions
161
+ - Corporate accounts
162
+
163
+ Contact our business development team at partnerships@toomanycables.com for more information.
knowledge_base/faqs/troubleshooting_guide.md ADDED
@@ -0,0 +1,402 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Technical Troubleshooting Guide - Too Many Cables
2
+
3
+ ## Quick Diagnostic Steps
4
+
5
+ ### Universal Troubleshooting Checklist
6
+ Before contacting support, try these basic steps for any cable issue:
7
+
8
+ 1. **Check Physical Connections**
9
+ - Ensure both ends are fully inserted
10
+ - Try inserting/removing cables several times
11
+ - Check for bent or damaged connectors
12
+ - Verify you're using the correct ports
13
+
14
+ 2. **Test with Known Good Components**
15
+ - Try cable with different devices
16
+ - Test devices with known working cables
17
+ - Use different ports on same device
18
+ - Test on different power sources
19
+
20
+ 3. **Power Cycle Everything**
21
+ - Turn off all connected devices
22
+ - Unplug power for 30 seconds
23
+ - Reconnect power and turn on display first
24
+ - Turn on source device last
25
+
26
+ 4. **Check Settings**
27
+ - Verify input/output settings on devices
28
+ - Check resolution and refresh rate settings
29
+ - Ensure correct mode selected (charging, data, video)
30
+ - Update device drivers if on computer
31
+
32
+ ## USB Cable Troubleshooting
33
+
34
+ ### USB-C Issues
35
+
36
+ #### Device Not Charging
37
+ **Symptoms**: No charging indicator, slow charging, intermittent charging
38
+
39
+ **Diagnostic Steps**:
40
+ 1. **Power Delivery Check**:
41
+ - Verify charger wattage matches device requirements
42
+ - Check if cable supports required power delivery
43
+ - Try original charger if available
44
+ - Test with lower-power charger to isolate issue
45
+
46
+ 2. **Connection Verification**:
47
+ - Clean USB-C ports with compressed air
48
+ - Try flipping cable (both orientations)
49
+ - Check for lint or debris in ports
50
+ - Ensure cable isn't loose in port
51
+
52
+ 3. **Device Settings**:
53
+ - Check charging settings in device menu
54
+ - Disable fast charging temporarily
55
+ - Try charging with device powered off
56
+ - Reset charging settings to default
57
+
58
+ **Solutions**:
59
+ - Use certified USB-C charger with adequate wattage
60
+ - Replace cable if power delivery insufficient
61
+ - Clean ports regularly to maintain connection
62
+ - Contact support if device won't charge with multiple cables
63
+
64
+ #### Data Transfer Problems
65
+ **Symptoms**: Device not recognized, slow transfer speeds, connection drops
66
+
67
+ **Diagnostic Steps**:
68
+ 1. **USB Mode Selection**:
69
+ - On Android: Select "File Transfer" or "MTP" mode
70
+ - On iOS: Trust the computer when prompted
71
+ - Check for "USB debugging" mode (Android)
72
+ - Try different USB connection modes
73
+
74
+ 2. **Driver Issues (Windows)**:
75
+ - Update USB drivers in Device Manager
76
+ - Try different USB ports (USB 3.0 vs 2.0)
77
+ - Restart Windows with device connected
78
+ - Install manufacturer's USB drivers
79
+
80
+ 3. **Cable Specification Check**:
81
+ - Verify cable supports data transfer (not just charging)
82
+ - Check USB version compatibility (2.0, 3.0, 3.1, 3.2)
83
+ - Ensure cable length appropriate for data speeds
84
+ - Test with shorter cable if available
85
+
86
+ **Solutions**:
87
+ - Use data-capable USB-C cable (not charging-only)
88
+ - Install proper device drivers
89
+ - Use USB 3.0+ ports for fastest speeds
90
+ - Keep cable length under 6 feet for optimal performance
91
+
92
+ ### USB-A Issues
93
+
94
+ #### Device Not Recognized
95
+ **Symptoms**: Computer doesn't detect connected device
96
+
97
+ **Diagnostic Steps**:
98
+ 1. **Port Testing**:
99
+ - Try all available USB ports
100
+ - Test both USB 2.0 and 3.0 ports
101
+ - Use front and back ports on desktop
102
+ - Test with USB hub if available
103
+
104
+ 2. **Power Issues**:
105
+ - Check if device powers on when connected
106
+ - Try powered USB hub for high-power devices
107
+ - Connect device to wall charger first
108
+ - Check USB port power settings in Windows
109
+
110
+ 3. **Driver Troubleshooting**:
111
+ - Open Device Manager and look for unknown devices
112
+ - Update or reinstall USB drivers
113
+ - Try on different computer to isolate issue
114
+ - Check manufacturer website for drivers
115
+
116
+ **Solutions**:
117
+ - Use powered USB hub for high-current devices
118
+ - Update USB controllers in Device Manager
119
+ - Try direct connection without USB hub
120
+ - Replace cable if multiple computers don't recognize device
121
+
122
+ ## HDMI Troubleshooting
123
+
124
+ ### No Video Signal
125
+
126
+ #### Black Screen Issues
127
+ **Symptoms**: Display shows "No Signal" or remains black
128
+
129
+ **Diagnostic Steps**:
130
+ 1. **Basic Connection Check**:
131
+ - Verify cable connected to correct HDMI input
132
+ - Try different HDMI ports on display
133
+ - Check if HDMI input is selected on TV/monitor
134
+ - Ensure both devices are powered on
135
+
136
+ 2. **Resolution Compatibility**:
137
+ - Start with lower resolution (1080p)
138
+ - Check maximum resolution supported by display
139
+ - Try different refresh rates (60Hz, 30Hz)
140
+ - Test with safe mode or basic video settings
141
+
142
+ 3. **HDCP Handshake Issues**:
143
+ - Power off both devices for 30 seconds
144
+ - Turn on display first, then source
145
+ - Try disabling HDCP on source device
146
+ - Test with different HDMI cable
147
+
148
+ **Solutions**:
149
+ - Use HDMI 2.1 cable for 4K@120Hz or 8K
150
+ - Enable "Enhanced HDMI" mode on TV
151
+ - Update graphics drivers on computer
152
+ - Try component or composite video as alternative
153
+
154
+ #### Intermittent Signal Loss
155
+ **Symptoms**: Picture cuts out periodically, flickering, snow
156
+
157
+ **Diagnostic Steps**:
158
+ 1. **Cable Integrity**:
159
+ - Inspect cable for physical damage
160
+ - Try different cable to isolate issue
161
+ - Check cable length (shorter is better)
162
+ - Ensure cable not bent sharply
163
+
164
+ 2. **Bandwidth Issues**:
165
+ - Reduce resolution or refresh rate
166
+ - Disable HDR temporarily
167
+ - Try HDMI 2.0 instead of 2.1 mode
168
+ - Check if cable supports required bandwidth
169
+
170
+ 3. **Interference Check**:
171
+ - Move cable away from power cables
172
+ - Check for nearby electromagnetic interference
173
+ - Try different HDMI port
174
+ - Test in different location
175
+
176
+ **Solutions**:
177
+ - Use higher quality cable for long runs
178
+ - Add ferrite cores to reduce interference
179
+ - Use active HDMI cable for distances over 15 feet
180
+ - Replace cable if intermittent connection continues
181
+
182
+ ### Audio Issues
183
+
184
+ #### No Audio Through HDMI
185
+ **Symptoms**: Video works but no audio from display or speakers
186
+
187
+ **Diagnostic Steps**:
188
+ 1. **Audio Output Settings**:
189
+ - Set HDMI as default audio device
190
+ - Check audio format settings (PCM vs Bitstream)
191
+ - Verify audio isn't muted on source device
192
+ - Try different audio format (stereo vs surround)
193
+
194
+ 2. **Display Audio Settings**:
195
+ - Check TV/monitor audio settings
196
+ - Verify internal speakers are enabled
197
+ - Test with headphones connected to display
198
+ - Check audio output selection on TV
199
+
200
+ 3. **Driver Issues**:
201
+ - Update audio drivers on computer
202
+ - Reinstall HDMI audio drivers
203
+ - Check Windows Sound control panel
204
+ - Try disabling other audio devices
205
+
206
+ **Solutions**:
207
+ - Enable HDMI audio in device settings
208
+ - Use PCM audio format for compatibility
209
+ - Update graphics and audio drivers
210
+ - Try different HDMI port on display
211
+
212
+ ## Network Cable Troubleshooting
213
+
214
+ ### Ethernet Connection Issues
215
+
216
+ #### No Network Connection
217
+ **Symptoms**: No internet, network adapter shows disconnected
218
+
219
+ **Diagnostic Steps**:
220
+ 1. **Link Status Check**:
221
+ - Look for link lights on network ports
222
+ - Check cable continuity with tester
223
+ - Try different ethernet ports
224
+ - Test cable with different devices
225
+
226
+ 2. **Cable Specification**:
227
+ - Verify cable category (Cat5e, Cat6, Cat6a)
228
+ - Check cable length (maximum 328 feet)
229
+ - Ensure straight-through cable (not crossover)
230
+ - Test with known good cable
231
+
232
+ 3. **Network Settings**:
233
+ - Check IP address configuration
234
+ - Try automatic IP settings (DHCP)
235
+ - Reset network adapter
236
+ - Update network drivers
237
+
238
+ **Solutions**:
239
+ - Use Cat6 cable for Gigabit speeds
240
+ - Replace cable if no link lights
241
+ - Check network adapter settings
242
+ - Contact IT support for network configuration
243
+
244
+ #### Slow Network Speeds
245
+ **Symptoms**: Connection works but speeds slower than expected
246
+
247
+ **Diagnostic Steps**:
248
+ 1. **Speed Testing**:
249
+ - Run speed test from multiple sources
250
+ - Test wired vs wireless speeds
251
+ - Check speeds at different times
252
+ - Compare with ISP advertised speeds
253
+
254
+ 2. **Cable Quality**:
255
+ - Verify cable supports required speed
256
+ - Check for interference from power cables
257
+ - Test with shorter cable
258
+ - Ensure cable not damaged or kinked
259
+
260
+ 3. **Network Configuration**:
261
+ - Check duplex settings (full vs half)
262
+ - Verify network adapter speed settings
263
+ - Test direct connection to modem
264
+ - Check for network congestion
265
+
266
+ **Solutions**:
267
+ - Use Cat6a cable for 10 Gigabit speeds
268
+ - Keep network cables away from power lines
269
+ - Update network drivers and firmware
270
+ - Check with ISP if speeds consistently low
271
+
272
+ ## Audio Cable Troubleshooting
273
+
274
+ ### 3.5mm Audio Issues
275
+
276
+ #### No Audio Output
277
+ **Symptoms**: No sound from headphones or speakers
278
+
279
+ **Diagnostic Steps**:
280
+ 1. **Connection Check**:
281
+ - Ensure plug fully inserted
282
+ - Try different audio jacks
283
+ - Check for loose connections
284
+ - Test with different devices
285
+
286
+ 2. **Device Settings**:
287
+ - Check audio output selection
288
+ - Verify volume levels not muted
289
+ - Try different audio sources
290
+ - Test with built-in speakers
291
+
292
+ 3. **Cable Testing**:
293
+ - Try different audio cable
294
+ - Check for cable damage
295
+ - Test with different headphones/speakers
296
+ - Verify cable compatibility (TRRS vs TRS)
297
+
298
+ **Solutions**:
299
+ - Clean audio jacks with compressed air
300
+ - Use appropriate cable type for device
301
+ - Check audio driver settings
302
+ - Replace cable if testing confirms failure
303
+
304
+ ## Power Cable Troubleshooting
305
+
306
+ ### AC Power Issues
307
+
308
+ #### Device Not Powering On
309
+ **Symptoms**: No power indicator, device completely dead
310
+
311
+ **Diagnostic Steps**:
312
+ 1. **Power Source Check**:
313
+ - Verify outlet has power
314
+ - Try different wall outlet
315
+ - Check circuit breaker/fuse
316
+ - Test with different devices
317
+
318
+ 2. **Cable Inspection**:
319
+ - Look for obvious cable damage
320
+ - Check connector for looseness
321
+ - Verify correct voltage/amperage rating
322
+ - Test with different power cable if available
323
+
324
+ 3. **Device Testing**:
325
+ - Try powering device with battery if available
326
+ - Check power button functionality
327
+ - Look for power indicator lights
328
+ - Try different power adapter if compatible
329
+
330
+ **Solutions**:
331
+ - Replace power cable if damaged
332
+ - Use proper voltage/amperage adapter
333
+ - Check device fuse if user replaceable
334
+ - Contact device manufacturer for internal issues
335
+
336
+ ## Advanced Diagnostics
337
+
338
+ ### Cable Testing Equipment
339
+ For professional troubleshooting:
340
+
341
+ 1. **Cable Testers**:
342
+ - Continuity testers for basic connectivity
343
+ - Network cable testers for ethernet
344
+ - HDMI signal analyzers for video cables
345
+ - USB testers for power and data
346
+
347
+ 2. **Multimeters**:
348
+ - Voltage testing for power cables
349
+ - Continuity testing for all cable types
350
+ - Resistance measurements
351
+ - Current draw testing
352
+
353
+ 3. **Oscilloscopes**:
354
+ - Signal quality analysis
355
+ - Timing measurements
356
+ - Noise and interference detection
357
+ - High-speed signal integrity
358
+
359
+ ### Environmental Factors
360
+ Consider these environmental impacts:
361
+
362
+ 1. **Temperature**:
363
+ - Extreme heat can damage cable insulation
364
+ - Cold temperatures can make cables stiff
365
+ - Thermal cycling can cause connector expansion
366
+
367
+ 2. **Humidity**:
368
+ - High humidity can cause corrosion
369
+ - Moisture can cause short circuits
370
+ - Condensation in connectors
371
+
372
+ 3. **Physical Stress**:
373
+ - Repeated bending at connection points
374
+ - Weight stress on connectors
375
+ - Vibration in mobile applications
376
+
377
+ ## When to Contact Support
378
+
379
+ ### Warranty Claims
380
+ Contact Too Many Cables support if:
381
+ - Troubleshooting steps don't resolve issue
382
+ - Cable fails within warranty period
383
+ - Multiple cables have same problem
384
+ - Device damage suspected from cable
385
+
386
+ ### Technical Support
387
+ We can help with:
388
+ - Advanced troubleshooting guidance
389
+ - Compatibility verification
390
+ - Replacement recommendations
391
+ - Custom cable solutions
392
+
393
+ ### Contact Methods
394
+ - **AI Chat**: Instant support at toomanycables.com
395
+ - **Phone**: 1-800-TMC-HELP
396
+ - **Email**: tech@toomanycables.com
397
+ - **Hours**: Monday-Friday 8 AM - 8 PM EST
398
+
399
+ ---
400
+
401
+ *Troubleshooting guide version 2.3 - Updated September 2024*
402
+ *For video troubleshooting guides, visit toomanycables.com/support*
knowledge_base/policies/customer_service_escalation.md ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Customer Service Escalation Policy
2
+
3
+ ## Dealing with Upset or Dissatisfied Customers
4
+
5
+ ### Overview
6
+ At TMC (Too Many Cables), we are committed to providing exceptional customer service and turning negative experiences into positive outcomes. This policy outlines the procedures for handling upset or dissatisfied customers.
7
+
8
+ ### Immediate Response Protocol
9
+
10
+ #### Step 1: Listen and Acknowledge
11
+ - Allow the customer to fully express their concerns without interruption
12
+ - Use active listening techniques: "I understand that...", "I can see why that would be frustrating..."
13
+ - Acknowledge their feelings and validate their experience
14
+ - Avoid defensive language or making excuses
15
+
16
+ #### Step 2: Apologize Sincerely
17
+ - Offer a genuine apology for their negative experience
18
+ - Take responsibility on behalf of the company
19
+ - Example: "I sincerely apologize for the inconvenience this has caused you"
20
+
21
+ #### Step 3: Investigate and Clarify
22
+ - Ask specific questions to understand the root cause
23
+ - Review tickets and any previous interactions
24
+ - Confirm understanding by summarizing the issue back to the customer
25
+
26
+ ### Resolution Strategies
27
+
28
+ #### Primary Solutions
29
+ 1. **Product Replacement**: For defective or damaged items
30
+ 2. **Full Refund**: When appropriate and within policy guidelines
31
+ 3. **Store Credit**: For exchanges or future purchases
32
+ 4. **Expedited Shipping**: For delayed orders at no additional cost
33
+
34
+ #### Compensation Guidelines
35
+ - **Minor Issues**: Apology and explanation may suffice
36
+ - **Moderate Issues**: Consider offering expedited shipping or small store credit
37
+ - **Significant Issues**: Full refund, replacement, or substantial store credit
38
+
39
+ ### Discount Code Authorization
40
+
41
+ #### WERESORRY10 Discount Code
42
+ When customers express significant dissatisfaction or have experienced notable inconvenience:
43
+
44
+ **Authorization Criteria:**
45
+ - Customer has experienced a genuine service failure
46
+ - Product defect or shipping delay has caused substantial frustration
47
+ - Multiple attempts to resolve the issue have been necessary
48
+ - Customer's tone indicates serious dissatisfaction
49
+
50
+ **Discount Details:**
51
+ - **Code**: WERESORRY10
52
+ - **Discount**: 10% off next purchase
53
+ - **Usage**: Single use only
54
+ - **Expiration**: 30 days from issue date
55
+ - **Minimum Order**: No minimum required
56
+
57
+ **When to Offer:**
58
+ - Defective products that caused inconvenience
59
+ - Significant shipping delays (>5 business days)
60
+ - Multiple customer service contacts for the same issue
61
+ - Billing errors or charge disputes
62
+ - Packaging damage resulting in product damage
63
+
64
+ **How to Present the Offer:**
65
+ "As an apology for this experience, I'd like to provide you with a 10% discount code for your next purchase. The code is WERESORRY10 and it's valid for 30 days. We value your business and want to make this right."
66
+
67
+ ### Escalation Procedures
68
+
69
+ #### Level 1: Customer Service Representative
70
+ - Handle routine complaints and minor issues
71
+ - Authorized to offer standard returns, exchanges, and WERESORRY10 discount
72
+ - Document all interactions in customer record
73
+
74
+ #### Level 2: Team Lead/Supervisor
75
+ - Complex issues requiring policy exceptions
76
+ - Authorized to approve higher-value refunds or store credits
77
+ - Multiple product issues or shipping problems
78
+
79
+ #### Level 3: Customer Service Manager
80
+ - Escalated complaints or threats of legal action
81
+ - Social media complaints or public negative reviews
82
+ - Requests for compensation beyond standard guidelines
83
+
84
+ ### Documentation Requirements
85
+
86
+ #### Interaction Logging
87
+ - Date and time of interaction
88
+ - Customer's primary concern
89
+ - Actions taken to resolve issue
90
+ - Compensation offered (if any)
91
+ - Customer's response and satisfaction level
92
+ - Follow-up required (Y/N)
93
+
94
+ #### Discount Code Tracking
95
+ - Record WERESORRY10 code usage in customer notes
96
+ - Include reason for discount authorization
97
+ - Monitor code redemption rates for policy effectiveness
98
+
99
+ ### Follow-Up Procedures
100
+
101
+ #### 48-Hour Check
102
+ - Contact customer within 48 hours to ensure satisfaction
103
+ - Confirm resolution was adequate
104
+ - Ask if any additional assistance is needed
105
+
106
+ #### 7-Day Follow-Up
107
+ - Email survey link for feedback on resolution process
108
+ - Monitor for discount code usage
109
+ - Update customer satisfaction metrics
110
+
111
+ ### Quality Assurance
112
+
113
+ #### Performance Metrics
114
+ - Customer satisfaction scores post-resolution
115
+ - First-contact resolution rate
116
+ - Discount code redemption rates
117
+ - Repeat complaint frequency
118
+
119
+ #### Continuous Improvement
120
+ - Monthly review of escalation patterns
121
+ - Analysis of discount code effectiveness
122
+ - Training updates based on common issues
123
+ - Policy adjustments based on customer feedback
124
+
125
+ ### Important Reminders
126
+
127
+ #### Do's
128
+ - Remain calm and professional at all times
129
+ - Take ownership of the customer's experience
130
+ - Offer solutions proactively
131
+ - Document everything thoroughly
132
+ - Follow up to ensure satisfaction
133
+
134
+ #### Don'ts
135
+ - Blame other departments or systems
136
+ - Make promises you can't keep
137
+ - Rush the customer off the phone/chat
138
+ - Ignore emotional aspects of their frustration
139
+ - Forget to document the interaction
140
+
141
+ ### Emergency Situations
142
+
143
+ #### Immediate Manager Involvement Required
144
+ - Threats of violence or self-harm
145
+ - Legal threats or mentions of attorneys
146
+ - Media contacts or influencer complaints
147
+ - Accusations of discrimination or harassment
148
+
149
+ #### Contact Information
150
+ - Team Lead: Extension 101
151
+ - Customer Service Manager: Extension 102
152
+ - Emergency Escalation Line: Extension 911
153
+
154
+ ### Training and Certification
155
+
156
+ All customer service representatives must complete:
157
+ - De-escalation techniques training
158
+ - Company policy certification
159
+ - Quarterly refresher sessions
160
+ - Role-playing exercises for difficult scenarios
161
+
162
+ ---
163
+
164
+ *This policy is reviewed quarterly and updated as needed. Last updated: Current Date*
165
+ *For questions about this policy, contact the Customer Service Manager*
knowledge_base/policies/return_warranty_policy.md ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Too Many Cables - Return and Warranty Policy
2
+
3
+ ## Return Policy
4
+
5
+ ### 30-Day Money-Back Guarantee
6
+ At Too Many Cables, we stand behind the quality of our products. If you're not completely satisfied with your purchase, you may return it within 30 days of delivery for a full refund or exchange.
7
+
8
+ ### Return Eligibility
9
+ **Items eligible for return:**
10
+ - All cables and accessories in original condition
11
+ - Items with original packaging (preferred but not required)
12
+ - Products purchased directly from Too Many Cables
13
+ - Items within 30 days of delivery date
14
+
15
+ **Items NOT eligible for return:**
16
+ - Custom or personalized cables
17
+ - Items damaged by misuse, negligence, or normal wear beyond 30 days
18
+ - Products purchased from unauthorized resellers
19
+
20
+ ### How to Initiate a Return
21
+ 1. **Contact Customer Service**: Reach out via our AI chat, email, or phone
22
+ 2. **Provide Order Information**: Order number, item description, and reason for return
23
+ 3. **Receive Return Authorization**: We'll email you a return authorization (RA) number
24
+ 4. **Ship the Item**: Use our prepaid return label (provided with RA number)
25
+ 5. **Receive Refund**: Processed within 3-5 business days of receipt
26
+
27
+ ### Return Shipping
28
+ - **Free Return Shipping**: We provide prepaid return labels for all returns
29
+ - **Original Shipping Costs**: Non-refundable unless item was defective or we sent wrong item
30
+ - **International Returns**: Contact customer service for specific instructions
31
+
32
+ ### Refund Processing
33
+ - **Processing Time**: 3-5 business days after we receive your return
34
+ - **Refund Method**: Same payment method used for original purchase
35
+ - **Credit Card Refunds**: May take 1-2 additional billing cycles to appear
36
+ - **Store Credit**: Available upon request, never expires
37
+
38
+ ## Lifetime Warranty
39
+
40
+ ### Comprehensive Coverage
41
+ Every Too Many Cables product comes with our industry-leading lifetime warranty. We guarantee our cables against defects in materials and workmanship for the life of the product.
42
+
43
+ ### What's Covered
44
+ **Manufacturing Defects:**
45
+ - Faulty connectors or internal wiring
46
+ - Premature failure of cable components
47
+ - Defects in materials or construction
48
+
49
+ **Performance Issues:**
50
+ - Cables that don't meet advertised specifications
51
+ - Intermittent connectivity problems
52
+ - Data transfer or charging speed issues
53
+
54
+ **Normal Wear and Tear:**
55
+ - Connector wear from regular use
56
+ - Cable jacket deterioration under normal conditions
57
+ - Internal wire damage from flexing during normal use
58
+
59
+ ### What's NOT Covered
60
+ **Physical Damage:**
61
+ - Cuts, crushes, or breaks from accidents
62
+ - Damage from pets (chewing, scratching)
63
+ - Damage from extreme temperatures or liquids
64
+ - Intentional damage or modification
65
+
66
+ **Misuse or Negligence:**
67
+ - Using cable for unintended purposes
68
+ - Exceeding voltage or current ratings
69
+ - Improper storage causing damage
70
+ - Commercial or industrial use beyond specifications
71
+
72
+ **Normal Limitations:**
73
+ - Gradual performance degradation over many years
74
+ - Cosmetic wear that doesn't affect functionality
75
+ - Compatibility issues with non-standard devices
76
+
77
+ ### Warranty Claims Process
78
+
79
+ #### Step 1: Contact Customer Service
80
+ - **AI Chat**: Available 24/7 for immediate assistance
81
+ - **Email**: warranty@toomanycables.com
82
+ - **Phone**: 1-800-TMC-HELP during business hours
83
+ - **Online Form**: Submit warranty claim through your account
84
+
85
+ #### Step 2: Provide Information
86
+ We'll need:
87
+ - Original order number or proof of purchase
88
+ - Product model/part number
89
+ - Description of the problem
90
+ - Photos of any visible damage (if applicable)
91
+
92
+ #### Step 3: Troubleshooting
93
+ Our support team will guide you through:
94
+ - Basic troubleshooting steps
95
+ - Compatibility verification
96
+ - Alternative solutions if applicable
97
+
98
+ #### Step 4: Warranty Determination
99
+ If troubleshooting doesn't resolve the issue:
100
+ - We'll determine if the problem is covered under warranty
101
+ - Approved claims receive immediate replacement authorization
102
+ - Disputed claims may require product return for inspection
103
+
104
+ #### Step 5: Replacement Processing
105
+ **For Approved Claims:**
106
+ - Replacement shipped same day (if in stock)
107
+ - Expedited shipping at no charge
108
+ - Tracking information provided immediately
109
+ - No need to return defective cable unless requested
110
+
111
+ #### Step 6: Follow-Up
112
+ - We'll check to ensure replacement resolves the issue
113
+ - Feedback collection to improve product quality
114
+ - Additional support if needed
115
+
116
+ ### Warranty Transfer
117
+ - Warranties are transferable to new owners
118
+ - Original proof of purchase required
119
+ - Same terms and conditions apply
120
+ - Contact customer service to update records
121
+
122
+ ### International Warranty
123
+ Our lifetime warranty applies worldwide:
124
+ - Same coverage terms globally
125
+ - Local customer service when available
126
+ - International shipping for replacements
127
+ - Customs and duties covered by Too Many Cables
128
+
129
+ ## Quality Assurance
130
+
131
+ ### Our Commitment to Quality
132
+ Under the leadership of Dr. Lisa Wang, our Head of Quality Assurance (PhD in Materials Science), every Too Many Cables product undergoes rigorous testing:
133
+
134
+ **Material Testing:**
135
+ - Conductor purity and gauge verification
136
+ - Insulation and jacket durability testing
137
+ - Connector plating quality inspection
138
+ - Environmental stress testing
139
+
140
+ **Performance Testing:**
141
+ - Data transfer speed verification
142
+ - Power delivery capability testing
143
+ - Signal integrity analysis
144
+ - Electromagnetic interference testing
145
+
146
+ **Durability Testing:**
147
+ - Flex cycle testing (10,000+ bends)
148
+ - Connector insertion/removal cycles
149
+ - Temperature and humidity exposure
150
+ - Abrasion and wear resistance
151
+
152
+ **Compliance Testing:**
153
+ - Industry standard compliance (USB-IF, HDMI, etc.)
154
+ - Safety certifications (UL, FCC, CE)
155
+ - Environmental regulations (RoHS, REACH)
156
+ - Quality management systems (ISO 9001:2015)
157
+
158
+ ### Continuous Improvement
159
+ We use warranty claims and customer feedback to:
160
+ - Identify potential quality issues
161
+ - Improve manufacturing processes
162
+ - Enhance product designs
163
+ - Update testing procedures
164
+
165
+ ## Customer Support Excellence
166
+
167
+ ### Our Support Philosophy
168
+ Customer satisfaction is our top priority. Our support team is trained to:
169
+ - Resolve issues quickly and fairly
170
+ - Provide expert technical guidance
171
+ - Offer personalized solutions
172
+ - Ensure positive customer experiences
173
+
174
+ ### Support Team Expertise
175
+ Our customer service representatives have:
176
+ - Technical training on all products
177
+ - Access to engineering and quality assurance teams
178
+ - Authority to make immediate warranty decisions
179
+ - Commitment to customer satisfaction
180
+
181
+ ### Escalation Process
182
+ If you're not satisfied with the initial response:
183
+ 1. Ask to speak with a supervisor
184
+ 2. Request escalation to management
185
+ 3. Contact our Customer Success team directly
186
+ 4. Reach out via social media for executive attention
187
+
188
+ ## Legal Terms
189
+
190
+ ### Warranty Limitations
191
+ This warranty is in lieu of all other warranties, express or implied, including merchantability and fitness for a particular purpose. Our liability is limited to repair or replacement of defective products.
192
+
193
+ ### Limitation of Liability
194
+ Too Many Cables shall not be liable for any incidental, consequential, or special damages arising from the use of our products. Maximum liability is limited to the purchase price of the product.
195
+
196
+ ### Dispute Resolution
197
+ Any disputes will be resolved through binding arbitration in accordance with the rules of the American Arbitration Association.
198
+
199
+ ---
200
+
201
+ **Questions about our return or warranty policy?**
202
+ Contact our customer service team:
203
+ - AI Chat: Available 24/7 on our website
204
+ - Email: support@toomanycables.com
205
+ - Phone: 1-800-TMC-HELP
206
+ - Mail: Too Many Cables Customer Service, [Corporate Address]
207
+
208
+ *Policy effective as of January 1, 2024. Subject to change without notice.*
knowledge_base/policies/shipping_customer_service.md ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Too Many Cables - Shipping and Customer Service Policy
2
+
3
+ ## Shipping Policy
4
+
5
+ ### Domestic Shipping (United States)
6
+
7
+ #### Standard Shipping
8
+ - **Processing Time**: Orders placed before 3 PM EST ship same day
9
+ - **Delivery Time**: 2-3 business days via USPS or UPS
10
+ - **Cost**: Free on orders over $25, $4.99 for orders under $25
11
+ - **Tracking**: Provided via email once order ships
12
+ - **Coverage**: All 50 states, APO/FPO addresses
13
+
14
+ #### Expedited Shipping Options
15
+ **Next Day Delivery:**
16
+ - **Delivery Time**: Next business day by 3 PM
17
+ - **Cost**: $14.99 (free on orders over $200)
18
+ - **Cutoff**: Orders must be placed by 12 PM EST
19
+ - **Availability**: Monday-Thursday (Friday orders deliver Monday)
20
+
21
+ **2-Day Express:**
22
+ - **Delivery Time**: 2 business days
23
+ - **Cost**: $9.99 (free on orders over $150)
24
+ - **Cutoff**: Orders must be placed by 3 PM EST
25
+ - **Availability**: Monday-Friday
26
+
27
+ #### Weekend and Holiday Shipping
28
+ - **Saturday Delivery**: Available for additional $5.99
29
+ - **Sunday Delivery**: Not available
30
+ - **Holiday Processing**: No processing on federal holidays
31
+ - **Holiday Rush**: Extended cutoff times during peak seasons
32
+
33
+ ### International Shipping
34
+
35
+ #### Available Countries
36
+ We ship to over 190 countries worldwide, including:
37
+ - **Tier 1** (5-7 business days): Canada, UK, EU, Australia, Japan
38
+ - **Tier 2** (7-14 business days): Most other countries
39
+ - **Restricted**: Some countries may have shipping restrictions
40
+
41
+ #### International Shipping Costs
42
+ - **Canada**: Starting at $12.99
43
+ - **EU/UK**: Starting at $15.99
44
+ - **Asia/Pacific**: Starting at $18.99
45
+ - **Other Countries**: Calculated at checkout
46
+ - **Free International**: Orders over $500
47
+
48
+ #### Customs and Duties
49
+ - **Declared Value**: Full retail value as required by law
50
+ - **Customs Forms**: Completed accurately for all shipments
51
+ - **Duties/Taxes**: Customer responsibility, varies by country
52
+ - **Customs Delays**: Not included in delivery estimates
53
+ - **Restricted Items**: Some cables may be restricted in certain countries
54
+
55
+ ### Special Shipping Situations
56
+
57
+ #### Large Orders (Commercial/Bulk)
58
+ - **Freight Shipping**: Available for orders over 50 lbs
59
+ - **Business Addresses**: Faster delivery to commercial locations
60
+ - **Wholesale Pricing**: Volume discounts available
61
+ - **Account Management**: Dedicated support for large customers
62
+ - **Custom Delivery**: White glove service available
63
+
64
+ #### APO/FPO Military Addresses
65
+ - **Shipping Method**: USPS Priority Mail only
66
+ - **Delivery Time**: 7-21 business days
67
+ - **Cost**: Same as domestic shipping
68
+ - **Restrictions**: Some high-value items may require signature
69
+ - **Documentation**: Military ID verification may be required
70
+
71
+ #### P.O. Box Delivery
72
+ - **USPS Only**: UPS/FedEx cannot deliver to P.O. boxes
73
+ - **Automatic Routing**: System selects appropriate carrier
74
+ - **Delivery Time**: Same as standard shipping
75
+ - **Restrictions**: Some expedited options not available
76
+ - **Size Limits**: Large packages may require pickup
77
+
78
+ ## Order Processing
79
+
80
+ ### Order Confirmation
81
+ - **Immediate Confirmation**: Email sent within minutes of order
82
+ - **Order Review**: All orders reviewed for accuracy
83
+ - **Inventory Check**: Real-time stock verification
84
+ - **Payment Processing**: Secure processing within 2 hours
85
+ - **Fraud Prevention**: Advanced security screening
86
+
87
+ ### Order Modifications
88
+ **Before Shipping:**
89
+ - **Changes Allowed**: Address, shipping method, item quantities
90
+ - **Contact Required**: Must contact customer service
91
+ - **Time Limit**: Changes accepted until order ships
92
+ - **Additional Charges**: May apply for expedited shipping
93
+
94
+ **After Shipping:**
95
+ - **Address Changes**: Contact carrier directly for delivery instructions
96
+ - **Intercept Service**: Available for additional fee through carriers
97
+ - **Return to Sender**: Full refund minus shipping costs
98
+ - **Reshipment**: New shipping charges apply
99
+
100
+ ### Inventory Management
101
+ - **Real-Time Updates**: Inventory updated continuously
102
+ - **Backorder Policy**: Customer notification if items unavailable
103
+ - **Substitutions**: Only with customer approval
104
+ - **Partial Shipments**: Available to get some items faster
105
+ - **Stock Alerts**: Email notifications when items back in stock
106
+
107
+ ## Customer Service Standards
108
+
109
+ ### Response Time Commitments
110
+ - **AI Chat**: Instant response 24/7
111
+ - **Email**: Response within 2 hours during business hours
112
+ - **Phone**: Average wait time under 30 seconds
113
+ - **Social Media**: Response within 1 hour during business hours
114
+ - **After Hours**: Emergency support available for urgent issues
115
+
116
+ ### Customer Service Hours
117
+ **Standard Support:**
118
+ - **Monday-Friday**: 8 AM - 8 PM EST
119
+ - **Saturday**: 9 AM - 5 PM EST
120
+ - **Sunday**: AI chat only, emergency phone support
121
+
122
+ **Holiday Hours:**
123
+ - **Major Holidays**: Reduced hours or closed
124
+ - **Black Friday/Cyber Monday**: Extended hours
125
+ - **Holiday Season**: Extended hours through New Year
126
+
127
+ ### Service Level Standards
128
+
129
+ #### First Contact Resolution
130
+ - **Target**: 85% of issues resolved on first contact
131
+ - **Escalation**: Complex issues escalated within 15 minutes
132
+ - **Follow-up**: Proactive follow-up within 24 hours
133
+ - **Satisfaction**: Customer satisfaction survey for all interactions
134
+
135
+ #### Issue Categories & Response Times
136
+ **Urgent Issues** (Response within 1 hour):
137
+ - Order delivery problems
138
+ - Defective products affecting critical systems
139
+ - Payment processing errors
140
+ - Security/privacy concerns
141
+
142
+ **Standard Issues** (Response within 4 hours):
143
+ - General product questions
144
+ - Compatibility inquiries
145
+ - Return/exchange requests
146
+ - Account management
147
+
148
+ **General Inquiries** (Response within 24 hours):
149
+ - Product recommendations
150
+ - Technical specifications
151
+ - Company information
152
+ - Partnership inquiries
153
+
154
+ ### Customer Service Philosophy
155
+
156
+ #### Our Commitment
157
+ - **Customer First**: Every decision prioritizes customer satisfaction
158
+ - **Proactive Support**: Anticipate and prevent issues when possible
159
+ - **Expert Knowledge**: Extensive product and technical training
160
+ - **Empowerment**: Representatives authorized to resolve issues immediately
161
+
162
+ #### Service Principles
163
+ 1. **Listen Actively**: Understand the customer's complete situation
164
+ 2. **Respond Quickly**: Provide timely, accurate information
165
+ 3. **Take Ownership**: See issues through to complete resolution
166
+ 4. **Exceed Expectations**: Go above and beyond when possible
167
+ 5. **Follow Through**: Ensure customer satisfaction after resolution
168
+
169
+ ## Quality Assurance
170
+
171
+ ### Order Accuracy
172
+ - **Pick Verification**: Double-check all items before packing
173
+ - **Quality Control**: Visual inspection of all products
174
+ - **Packaging Standards**: Protective packaging for all shipments
175
+ - **Documentation**: Packing slip accuracy verification
176
+ - **Error Rate**: Target less than 0.1% order errors
177
+
178
+ ### Damage Prevention
179
+ - **Packaging Materials**: High-quality protective materials
180
+ - **Fragile Items**: Special handling procedures
181
+ - **Weather Protection**: Moisture-resistant packaging
182
+ - **Carrier Requirements**: Compliance with all carrier standards
183
+ - **Insurance**: Automatic coverage on high-value shipments
184
+
185
+ ### Customer Feedback Integration
186
+ - **Review Analysis**: Regular review of customer feedback
187
+ - **Process Improvement**: Continuous improvement based on feedback
188
+ - **Training Updates**: Staff training updated based on common issues
189
+ - **Policy Updates**: Policies updated to address customer needs
190
+
191
+ ## Problem Resolution
192
+
193
+ ### Common Issues & Solutions
194
+
195
+ #### Shipping Delays
196
+ **Causes**: Weather, carrier delays, high volume periods
197
+ **Solutions**:
198
+ - Proactive communication to affected customers
199
+ - Expedited replacement shipping at no charge
200
+ - Full refund if unacceptable delay
201
+ - Compensation for critical delivery failures
202
+
203
+ #### Damaged Packages
204
+ **Process**:
205
+ 1. Customer photos of damage documented
206
+ 2. Immediate replacement authorization
207
+ 3. Carrier claim filed automatically
208
+ 4. Customer receives replacement within 24 hours
209
+ 5. No need to return damaged item unless requested
210
+
211
+ #### Lost Packages
212
+ **Response**:
213
+ - Carrier tracking investigation initiated
214
+ - Replacement shipped immediately
215
+ - Insurance claim processed
216
+ - Delivery confirmation required going forward
217
+ - Address verification for future orders
218
+
219
+ ### Escalation Procedures
220
+
221
+ #### Level 1: Customer Service Representative
222
+ - Standard issue resolution
223
+ - Policy explanation and application
224
+ - Basic troubleshooting assistance
225
+ - Order modifications and updates
226
+
227
+ #### Level 2: Customer Service Supervisor
228
+ - Complex technical issues
229
+ - Policy exceptions and special circumstances
230
+ - Complaint resolution
231
+ - Quality assurance issues
232
+
233
+ #### Level 3: Customer Success Manager
234
+ - Executive complaints
235
+ - Major account issues
236
+ - Process improvement feedback
237
+ - Partnership and wholesale inquiries
238
+
239
+ #### Executive Level: Leadership Team
240
+ - Corporate policy issues
241
+ - Legal or regulatory matters
242
+ - Media or public relations issues
243
+ - Strategic partnership opportunities
244
+
245
+ ## Continuous Improvement
246
+
247
+ ### Performance Metrics
248
+ - **Customer Satisfaction Score**: Target 95%+
249
+ - **First Call Resolution**: Target 85%+
250
+ - **Average Response Time**: Under 2 hours
251
+ - **Order Accuracy**: 99.9%+
252
+ - **On-Time Delivery**: 98%+
253
+
254
+ ### Regular Reviews
255
+ - **Monthly Performance Reviews**: Team and individual metrics
256
+ - **Quarterly Policy Updates**: Based on customer feedback
257
+ - **Annual Training**: Comprehensive update training
258
+ - **Customer Advisory Panel**: Regular feedback sessions
259
+
260
+ ### Technology Integration
261
+ - **CRM System**: Complete customer interaction history
262
+ - **AI Assistance**: Advanced chatbot for instant support
263
+ - **Predictive Analytics**: Anticipate customer needs
264
+ - **Mobile Optimization**: Full mobile customer service capability
265
+
266
+ ## Contact Information
267
+
268
+ ### Customer Service Channels
269
+ - **Phone**: 1-800-TMC-HELP (1-800-862-4357)
270
+ - **Email**: support@toomanycables.com
271
+ - **Live Chat**: Available 24/7 at toomanycables.com
272
+ - **Social Media**: @TooManyCables on Twitter, Facebook, Instagram
273
+
274
+ ### Specialized Support
275
+ - **Technical Support**: tech@toomanycables.com
276
+ - **Warranty Claims**: warranty@toomanycables.com
277
+ - **Business Sales**: business@toomanycables.com
278
+ - **Partnership Inquiries**: partnerships@toomanycables.com
279
+
280
+ ### Mailing Address
281
+ Too Many Cables Customer Service
282
+ [Corporate Headquarters Address]
283
+ [City, State ZIP Code]
284
+
285
+ ---
286
+
287
+ *Policy effective September 2024 - Subject to periodic updates*
288
+ *For the most current version, visit toomanycables.com/policies*
knowledge_base/product_manuals/audio_cable.md ADDED
@@ -0,0 +1,276 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Audio Cable Product Manual
2
+
3
+ ## Product Overview
4
+
5
+ Too Many Cables 3.5mm Audio Cable delivers high-quality stereo audio transmission with premium gold-plated connectors, tangle-free design, and universal compatibility for all audio devices with standard 3.5mm headphone jacks.
6
+
7
+ ## Product Specifications
8
+
9
+ ### TMC-AUDIO-3.5MM-6FT
10
+ - **Length**: 6 feet (1.8 meters)
11
+ - **Connector Type**: 3.5mm stereo male to 3.5mm stereo male
12
+ - **Conductor**: High-purity oxygen-free copper (OFC)
13
+ - **Insulation**: Low-loss PE dielectric
14
+ - **Shielding**: 95% coverage braided copper shield
15
+ - **Jacket**: Flexible PVC with tangle-resistant design
16
+ - **Connectors**: 24k gold-plated for corrosion resistance
17
+ - **Impedance**: 75 ohms
18
+ - **Frequency Response**: 20Hz - 20kHz
19
+ - **Signal-to-Noise Ratio**: >90dB
20
+ - **Cross Talk**: <-40dB
21
+ - **Weight**: 2.1 oz (60g)
22
+
23
+ ## Audio Performance
24
+
25
+ ### Signal Quality
26
+ - **Frequency Response**: Flat 20Hz to 20kHz (±0.5dB)
27
+ - **Total Harmonic Distortion**: <0.1% at 1kHz
28
+ - **Signal-to-Noise Ratio**: >90dB
29
+ - **Channel Separation**: >40dB at 1kHz
30
+ - **Maximum Input Level**: 2V RMS
31
+
32
+ ### Impedance Characteristics
33
+ - **Cable Impedance**: 75 ohms
34
+ - **Capacitance**: 30pF per foot
35
+ - **Resistance**: <0.1 ohms per conductor
36
+ - **Compatible Load Impedance**: 8 ohms to 10k ohms
37
+
38
+ ## Compatibility Guide
39
+
40
+ ### Source Devices
41
+ **Smartphones:**
42
+ - iPhone (all models with 3.5mm jack or adapter)
43
+ - Samsung Galaxy series
44
+ - Google Pixel series (with adapter)
45
+ - Most Android phones with 3.5mm jack
46
+ - Older smartphones with built-in audio jack
47
+
48
+ **Audio Players:**
49
+ - iPod (all models with 3.5mm output)
50
+ - Portable CD players
51
+ - MP3 players
52
+ - Digital audio players (DAPs)
53
+ - Walkmans and portable cassette players
54
+
55
+ **Computers & Laptops:**
56
+ - Desktop computers (line out/headphone jack)
57
+ - Laptops with 3.5mm audio output
58
+ - Tablets with audio jack
59
+ - Gaming laptops
60
+ - Workstations with audio output
61
+
62
+ **Audio Equipment:**
63
+ - Headphone amplifiers
64
+ - Audio interfaces
65
+ - Mixing consoles
66
+ - Portable speakers
67
+ - Car stereos with aux input
68
+ - Home stereo systems
69
+
70
+ **Gaming Devices:**
71
+ - Nintendo Switch (handheld mode)
72
+ - PlayStation Portable (PSP)
73
+ - Nintendo 3DS/2DS
74
+ - Retro gaming consoles
75
+ - Gaming headset splitters
76
+
77
+ ### Output Devices
78
+ **Headphones & Earphones:**
79
+ - Over-ear headphones
80
+ - On-ear headphones
81
+ - In-ear monitors (IEMs)
82
+ - Earbuds and earphones
83
+ - Studio monitor headphones
84
+
85
+ **Speakers:**
86
+ - Portable Bluetooth speakers (aux input)
87
+ - Desktop computer speakers
88
+ - Bookshelf speakers with 3.5mm input
89
+ - Powered studio monitors
90
+ - Car speakers via aux input
91
+
92
+ **Audio Systems:**
93
+ - Home stereo receivers
94
+ - Amplifiers with 3.5mm input
95
+ - PA systems
96
+ - Recording equipment
97
+ - Audio mixers
98
+
99
+ ## Usage Instructions
100
+
101
+ ### Basic Connection
102
+ 1. Identify source device 3.5mm output
103
+ 2. Identify target device 3.5mm input
104
+ 3. Insert connectors fully into both devices
105
+ 4. Ensure secure connection (click into place)
106
+ 5. Test audio playback and adjust volume
107
+
108
+ ### Optimal Setup
109
+ - **Clean Connections**: Ensure jacks are clean and debris-free
110
+ - **Secure Fit**: Push connectors fully into jacks
111
+ - **Strain Relief**: Avoid sharp bends near connectors
112
+ - **Volume Levels**: Start with low volume and increase gradually
113
+
114
+ ### Cable Management
115
+ - **Tangle Prevention**: Use loose coiling for storage
116
+ - **Avoid Stress**: Don't pull on connectors
117
+ - **Proper Storage**: Coil loosely when not in use
118
+ - **Heat Protection**: Keep away from heat sources
119
+
120
+ ## Technical Specifications
121
+
122
+ ### Electrical Characteristics
123
+ - **Conductor Material**: Oxygen-free copper (OFC)
124
+ - **Conductor Gauge**: 26 AWG
125
+ - **Shield Coverage**: 95% braided copper
126
+ - **Jacket Material**: Flexible PVC
127
+ - **Connector Plating**: 24k gold (15μ" thickness)
128
+
129
+ ### Mechanical Properties
130
+ - **Bend Radius**: 5x cable diameter minimum
131
+ - **Pull Strength**: 50 lbs minimum
132
+ - **Connector Retention**: 22 lbs minimum
133
+ - **Flex Life**: >10,000 cycles
134
+ - **Temperature Rating**: -20°C to +60°C
135
+
136
+ ### Audio Performance Specifications
137
+ - **Bandwidth**: DC to 100MHz
138
+ - **Insertion Loss**: <0.1dB at 20kHz
139
+ - **Return Loss**: >20dB (20Hz-20kHz)
140
+ - **Crosstalk**: <-40dB at 10kHz
141
+ - **Propagation Delay**: 1.5ns per foot
142
+
143
+ ### Environmental Ratings
144
+ - **Operating Temperature**: -4°F to 140°F (-20°C to 60°C)
145
+ - **Storage Temperature**: -40°F to 185°F (-40°C to 85°C)
146
+ - **Humidity**: 5% to 95% RH (non-condensing)
147
+ - **Altitude**: Up to 10,000 feet (3,000m)
148
+
149
+ ## Audio Quality Features
150
+
151
+ ### Superior Materials
152
+ - **OFC Conductors**: Reduces signal loss and distortion
153
+ - **PE Dielectric**: Low-loss insulation for clarity
154
+ - **Braided Shield**: Minimizes electromagnetic interference
155
+ - **Gold Plating**: Prevents corrosion and ensures reliable connection
156
+
157
+ ### Noise Reduction
158
+ - **Shielding**: 95% coverage protects against EMI/RFI
159
+ - **Twisted Pair**: Reduces crosstalk between channels
160
+ - **Low Capacitance**: Maintains high-frequency response
161
+ - **Strain Relief**: Prevents intermittent connections
162
+
163
+ ## Troubleshooting
164
+
165
+ ### Common Issues
166
+
167
+ **No Audio Output**
168
+ - Check volume levels on both devices
169
+ - Verify cable is fully inserted in both jacks
170
+ - Test cable with different devices
171
+ - Check if devices are muted
172
+ - Try different audio source
173
+
174
+ **Poor Audio Quality**
175
+ - Clean connector contacts
176
+ - Check for loose connections
177
+ - Verify cable isn't damaged
178
+ - Test with different audio content
179
+ - Check device audio settings
180
+
181
+ **Audio Only in One Channel**
182
+ - Ensure cable is fully inserted
183
+ - Check for bent connectors
184
+ - Test cable with different devices
185
+ - Verify source audio is stereo
186
+ - Check device balance settings
187
+
188
+ **Intermittent Audio**
189
+ - Check for loose connections
190
+ - Inspect cable for damage
191
+ - Clean contact surfaces
192
+ - Avoid cable stress/bending
193
+ - Test in different positions
194
+
195
+ **Background Noise/Hum**
196
+ - Check for interference sources
197
+ - Ensure proper grounding
198
+ - Move away from power cables
199
+ - Check gain/volume levels
200
+ - Try different cable routing
201
+
202
+ ### Advanced Troubleshooting
203
+ - **Impedance Matching**: Verify compatible impedances
204
+ - **Signal Levels**: Check if levels are appropriate
205
+ - **Grounding Issues**: Ensure proper system grounding
206
+ - **Cable Testing**: Test continuity with multimeter
207
+
208
+ ## Care & Maintenance
209
+
210
+ ### Cleaning Instructions
211
+ - **Disconnect**: Remove from devices before cleaning
212
+ - **Dry Cleaning**: Use lint-free cloth for cable jacket
213
+ - **Connector Care**: Clean with isopropyl alcohol if needed
214
+ - **Avoid Moisture**: Keep connectors dry
215
+ - **Storage**: Coil loosely to prevent damage
216
+
217
+ ### Preventive Maintenance
218
+ - **Regular Inspection**: Check for wear or damage
219
+ - **Proper Storage**: Avoid tight coiling or knotting
220
+ - **Stress Relief**: Support cable weight at connections
221
+ - **Temperature**: Store in moderate temperature environment
222
+
223
+ ## What's Included
224
+
225
+ ### Package Contents
226
+ - 1x TMC 3.5mm Audio Cable (6ft)
227
+ - 1x Cable management velcro strap
228
+ - 1x Quick Reference Guide
229
+ - 1x Warranty Registration Card
230
+
231
+ ## Warranty & Support
232
+
233
+ ### Warranty Coverage
234
+ - **Duration**: Lifetime limited warranty
235
+ - **Coverage**: Manufacturing defects and material failures
236
+ - **Exclusions**: Physical damage, misuse, normal wear
237
+
238
+ ### Customer Support
239
+ - **Website**: support.toomanycables.com/audio
240
+ - **Email**: support@toomanycables.com
241
+ - **Phone**: 1-800-TMC-HELP
242
+ - **Live Chat**: Available 24/7 on website
243
+
244
+ ### Warranty Registration
245
+ Register for:
246
+ - Lifetime warranty activation
247
+ - Product support notifications
248
+ - Technical assistance
249
+ - Replacement cable discounts
250
+
251
+ ## Applications
252
+
253
+ ### Professional Audio
254
+ - **Studio Recording**: Connect instruments to audio interfaces
255
+ - **Live Sound**: Patch cables for mixing consoles
256
+ - **DJ Setup**: Connect devices to mixers
257
+ - **Broadcasting**: Studio equipment connections
258
+
259
+ ### Consumer Audio
260
+ - **Home Theater**: Connect devices to receivers
261
+ - **Car Audio**: Phone to car stereo connection
262
+ - **Portable Audio**: Connect players to speakers
263
+ - **Gaming**: Audio connections for gaming setups
264
+
265
+ ### Educational/Business
266
+ - **Presentations**: Connect laptops to PA systems
267
+ - **Classrooms**: Audio visual equipment connections
268
+ - **Conference Rooms**: Audio system integration
269
+ - **Training Facilities**: Equipment interconnection
270
+
271
+ ---
272
+
273
+ **Model**: TMC-AUDIO-3.5MM-6FT
274
+ **Manual Version**: 1.2
275
+ **Last Updated**: October 2025
276
+ **Document**: TMC-AUDIO-MANUAL-V1.2
knowledge_base/product_manuals/charging_hub.md ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Multi-Port Charging Hub Product Manual
2
+
3
+ ## Product Overview
4
+
5
+ Too Many Cables Multi-Port Charging Hub provides intelligent charging for up to 6 devices simultaneously with 100W total power output and smart charging technology that automatically detects and delivers optimal charging speeds for each connected device.
6
+
7
+ ## Product Specifications
8
+
9
+ ### TMC-CHARGEHUB-100W-6PORT
10
+ - **Total Power Output**: 100W
11
+ - **Port Configuration**:
12
+ - 4x USB-A ports (12W each, 48W total)
13
+ - 2x USB-C PD ports (52W total, single port max 65W)
14
+ - **Smart Charging**: Auto-detect device requirements
15
+ - **Safety Features**: Over-current, over-voltage, over-temperature protection
16
+ - **Input**: AC 100-240V, 50/60Hz
17
+ - **Dimensions**: 5.5" x 3.5" x 1.2" (140 x 89 x 30mm)
18
+ - **Weight**: 12 oz (340g)
19
+ - **Material**: Fire-resistant ABS plastic housing
20
+ - **LED Indicators**: Power and charging status per port
21
+ - **Cable**: 6ft detachable AC power cord
22
+
23
+ ## Compatibility Guide
24
+
25
+ ### Compatible Devices
26
+ **Smartphones:**
27
+ - iPhone (all models with Lightning or USB-C)
28
+ - Samsung Galaxy series
29
+ - Google Pixel series
30
+ - OnePlus devices
31
+ - Most Android smartphones
32
+
33
+ **Tablets:**
34
+ - iPad (all models)
35
+ - Samsung Galaxy Tab series
36
+ - Microsoft Surface tablets
37
+ - Android tablets
38
+
39
+ **Laptops & Computers:**
40
+ - MacBook Air/Pro (via USB-C PD)
41
+ - Dell XPS series (via USB-C PD)
42
+ - HP Spectre series (via USB-C PD)
43
+ - Chromebooks with USB-C charging
44
+ - Nintendo Switch
45
+
46
+ **Other Devices:**
47
+ - Wireless earbuds/headphones
48
+ - Smartwatches
49
+ - Power banks
50
+ - Portable speakers
51
+ - Gaming controllers
52
+
53
+ ## Smart Charging Technology
54
+
55
+ ### Intelligent Power Distribution
56
+ - **Dynamic Power Allocation**: Automatically adjusts power output based on connected devices
57
+ - **Device Recognition**: Identifies device type and optimal charging profile
58
+ - **Priority Charging**: Laptop/tablet charging takes priority when multiple devices connected
59
+
60
+ ### Charging Profiles
61
+ - **USB-A Ports**: 5V/2.4A max per port (12W)
62
+ - **USB-C Port 1**: 5V/3A, 9V/3A, 12V/3A, 15V/3A, 20V/3.25A (65W max)
63
+ - **USB-C Port 2**: 5V/3A, 9V/2A, 12V/1.5A (18W max when both ports used)
64
+
65
+ ## Usage Instructions
66
+
67
+ ### Initial Setup
68
+ 1. Connect AC power cord to charging hub
69
+ 2. Plug power cord into wall outlet (100-240V)
70
+ 3. Power LED should illuminate blue
71
+ 4. Hub is ready for device charging
72
+
73
+ ### Device Charging
74
+ 1. Connect devices using appropriate cables
75
+ 2. Hub automatically detects device requirements
76
+ 3. Charging begins immediately
77
+ 4. LED indicators show charging status per port
78
+ 5. Disconnect devices when charging complete
79
+
80
+ ### LED Status Indicators
81
+ - **Blue**: Hub powered on and ready
82
+ - **Green**: Device charging normally
83
+ - **Orange**: Fast charging active
84
+ - **Red**: Error or overload condition
85
+ - **Off**: No device connected or hub not powered
86
+
87
+ ## Safety Features
88
+
89
+ ### Protection Systems
90
+ - **Over-Current Protection**: Prevents damage from excessive current draw
91
+ - **Over-Voltage Protection**: Protects against voltage spikes
92
+ - **Over-Temperature Protection**: Automatic shutdown if overheating detected
93
+ - **Short-Circuit Protection**: Immediate shutdown on short circuit
94
+ - **Surge Protection**: Built-in surge suppression
95
+
96
+ ### Certifications
97
+ - **FCC Certified**: Electromagnetic compatibility
98
+ - **UL Listed**: Safety standards compliance
99
+ - **Energy Star**: Energy efficiency rating
100
+ - **RoHS Compliant**: Environmental safety standards
101
+
102
+ ## Troubleshooting
103
+
104
+ ### Common Issues
105
+
106
+ **Hub Not Powering On**
107
+ - Check AC power connection
108
+ - Verify wall outlet is working
109
+ - Try different power outlet
110
+ - Contact support if issue persists
111
+
112
+ **Device Not Charging**
113
+ - Verify cable is properly connected
114
+ - Try different USB port on hub
115
+ - Test with known working cable
116
+ - Check device charging port for debris
117
+
118
+ **Slow Charging Speed**
119
+ - Verify using appropriate cable for device
120
+ - Check total power draw (may need to disconnect some devices)
121
+ - Ensure device supports fast charging
122
+ - Clean charging contacts
123
+
124
+ **LED Indicators Not Working**
125
+ - Check power connection
126
+ - Verify hub is receiving power
127
+ - Contact support for LED replacement
128
+
129
+ ### Error Conditions
130
+ - **Red LED**: Overload condition - disconnect some devices
131
+ - **Hub Shutdown**: Overheating - allow cooling time, check ventilation
132
+ - **No Charging**: Verify compatible charging cable and device
133
+
134
+ ## Technical Specifications
135
+
136
+ ### Electrical Ratings
137
+ - **Input Voltage**: AC 100-240V ± 10%
138
+ - **Input Frequency**: 50/60Hz ± 3Hz
139
+ - **Input Current**: 2.5A max at 100V
140
+ - **Power Factor**: >0.9 at full load
141
+ - **Efficiency**: >85% at rated load
142
+
143
+ ### Environmental Conditions
144
+ - **Operating Temperature**: 32°F to 95°F (0°C to 35°C)
145
+ - **Storage Temperature**: -4°F to 140°F (-20°C to 60°C)
146
+ - **Humidity**: 10% to 90% RH (non-condensing)
147
+ - **Altitude**: Up to 6,600 feet (2,000m)
148
+
149
+ ### Physical Specifications
150
+ - **Dimensions**: 5.5" L x 3.5" W x 1.2" H
151
+ - **Weight**: 12 oz (340g)
152
+ - **Housing Material**: Fire-resistant ABS plastic
153
+ - **Color**: Matte black with blue accents
154
+
155
+ ## Warranty & Support
156
+
157
+ ### Warranty Coverage
158
+ - **Duration**: 3-year limited warranty
159
+ - **Coverage**: Manufacturing defects and material failures
160
+ - **Exclusions**: Physical damage, misuse, normal wear
161
+
162
+ ### Customer Support
163
+ - **Website**: support.toomanycables.com/charginghub
164
+ - **Email**: support@toomanycables.com
165
+ - **Phone**: 1-800-TMC-HELP
166
+ - **Live Chat**: Available 24/7 on website
167
+ - **Support Hours**: Monday-Friday 8AM-8PM EST
168
+
169
+ ### Warranty Registration
170
+ Register your product within 30 days of purchase for:
171
+ - Extended warranty coverage
172
+ - Product update notifications
173
+ - Priority customer support
174
+ - Replacement part availability
175
+
176
+ ---
177
+
178
+ **Model**: TMC-CHARGEHUB-100W-6PORT
179
+ **Manual Version**: 2.1
180
+ **Last Updated**: October 2025
181
+ **Document**: TMC-CHG-HUB-MANUAL-V2.1
knowledge_base/product_manuals/hdmi_cables.md ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # HDMI Cable Product Manual
2
+
3
+ ## Product Overview
4
+
5
+ Too Many Cables HDMI cables deliver crystal-clear 4K and 8K video with immersive audio for the ultimate home theater and gaming experience. Our premium cables feature high-speed data transmission, advanced shielding, and gold-plated connectors for reliable, long-lasting connections.
6
+
7
+ ## Product Specifications
8
+
9
+ ### TMC-HDMI-8K-10FT (Ultra High Speed HDMI 2.1)
10
+ - **Length**: 10 feet (3 meters)
11
+ - **Maximum Resolution**: 8K@60Hz, 4K@120Hz
12
+ - **Bandwidth**: 48 Gbps
13
+ - **HDR Support**: HDR10, HDR10+, Dolby Vision
14
+ - **Audio**: eARC, Dolby Atmos, DTS:X
15
+ - **Gaming Features**: VRR, ALLM, QMS, QFT
16
+ - **Connector**: HDMI Type A (Standard)
17
+ - **Material**: Premium braided jacket, gold-plated connectors
18
+
19
+ ### TMC-HDMI-4K-6FT (High Speed HDMI 2.0)
20
+ - **Length**: 6 feet (1.8 meters)
21
+ - **Maximum Resolution**: 4K@60Hz, 1440p@144Hz
22
+ - **Bandwidth**: 18 Gbps
23
+ - **HDR Support**: HDR10, HDR10+
24
+ - **Audio**: ARC, Dolby TrueHD, DTS-HD
25
+ - **Gaming Features**: Basic VRR support
26
+ - **Connector**: HDMI Type A (Standard)
27
+ - **Material**: Durable PVC jacket, gold-plated connectors
28
+
29
+ ### TMC-HDMI-MINI-3FT (Mini HDMI to HDMI)
30
+ - **Length**: 3 feet (0.9 meters)
31
+ - **Maximum Resolution**: 4K@30Hz
32
+ - **Bandwidth**: 10.2 Gbps
33
+ - **HDR Support**: Basic HDR10
34
+ - **Audio**: Standard audio formats
35
+ - **Connector**: Mini HDMI (Type C) to Standard HDMI (Type A)
36
+ - **Material**: Flexible cable design, gold-plated connectors
37
+
38
+ ### TMC-HDMI-MICRO-3FT (Micro HDMI to HDMI)
39
+ - **Length**: 3 feet (0.9 meters)
40
+ - **Maximum Resolution**: 4K@30Hz
41
+ - **Bandwidth**: 10.2 Gbps
42
+ - **HDR Support**: Basic HDR10
43
+ - **Audio**: Standard audio formats
44
+ - **Connector**: Micro HDMI (Type D) to Standard HDMI (Type A)
45
+ - **Material**: Ultra-flexible design, gold-plated connectors
46
+
47
+ ## Compatibility Guide
48
+
49
+ ### Source Devices
50
+ **Gaming Consoles:**
51
+ - PlayStation 5 (requires HDMI 2.1 for 4K@120Hz)
52
+ - Xbox Series X/S (requires HDMI 2.1 for full features)
53
+ - PlayStation 4/4 Pro (HDMI 2.0 sufficient)
54
+ - Xbox One/One X (HDMI 2.0 sufficient)
55
+ - Nintendo Switch (Mini HDMI cable required)
56
+
57
+ **Computers & Laptops:**
58
+ - Desktop graphics cards (RTX 30/40 series, RX 6000/7000 series)
59
+ - Gaming laptops with HDMI output
60
+ - MacBook Pro/Air (with HDMI port or adapter)
61
+ - Mini PCs and Intel NUCs
62
+ - Tablets with HDMI/Mini HDMI output
63
+
64
+ **Media Devices:**
65
+ - Apple TV 4K (HDMI 2.1 recommended)
66
+ - Nvidia Shield TV Pro
67
+ - Roku Ultra, Amazon Fire TV Stick 4K Max
68
+ - Chromecast with Google TV
69
+ - Cable/satellite boxes with 4K support
70
+
71
+ ### Display Devices
72
+ **TVs:**
73
+ - 4K/8K Smart TVs (Samsung, LG, Sony, TCL)
74
+ - OLED and QLED displays
75
+ - Gaming-focused TVs with HDMI 2.1
76
+ - Projectors with 4K support
77
+
78
+ **Monitors:**
79
+ - 4K gaming monitors (144Hz+)
80
+ - Professional displays for content creation
81
+ - Ultrawide monitors with 4K resolution
82
+ - High refresh rate gaming displays
83
+
84
+ ## Performance Features
85
+
86
+ ### Video Quality
87
+ - **8K Resolution**: 7680x4320 pixels at 60Hz
88
+ - **4K Gaming**: 3840x2160 at 120Hz for smooth gameplay
89
+ - **High Dynamic Range**: Enhanced contrast and color
90
+ - **Wide Color Gamut**: BT.2020 color space support
91
+ - **10-Bit Color**: Over 1 billion colors for smooth gradients
92
+
93
+ ### Audio Quality
94
+ - **Enhanced Audio Return Channel (eARC)**: Full-bandwidth audio
95
+ - **Object-Based Audio**: Dolby Atmos and DTS:X support
96
+ - **High-Resolution Audio**: Up to 192kHz/24-bit
97
+ - **Multi-Channel**: Up to 32 audio channels
98
+ - **Audio Sync**: Automatic lip-sync correction
99
+
100
+ ### Gaming Features
101
+ - **Variable Refresh Rate (VRR)**: Eliminates screen tearing
102
+ - **Auto Low Latency Mode (ALLM)**: Reduces input lag automatically
103
+ - **Quick Media Switching (QMS)**: Faster source switching
104
+ - **Quick Frame Transport (QFT)**: Reduced latency for competitive gaming
105
+
106
+ ## Resolution & Refresh Rate Guide
107
+
108
+ ### HDMI 2.1 Cables (8K Series)
109
+ **Supported Resolutions:**
110
+ - 8K (7680x4320): 60Hz, 30Hz
111
+ - 4K (3840x2160): 120Hz, 60Hz, 30Hz
112
+ - 1440p (2560x1440): 144Hz, 120Hz, 60Hz
113
+ - 1080p (1920x1080): 240Hz, 144Hz, 120Hz, 60Hz
114
+
115
+ ### HDMI 2.0 Cables (4K Series)
116
+ **Supported Resolutions:**
117
+ - 4K (3840x2160): 60Hz, 30Hz
118
+ - 1440p (2560x1440): 144Hz, 120Hz, 60Hz
119
+ - 1080p (1920x1080): 144Hz, 120Hz, 60Hz
120
+ - 720p (1280x720): All refresh rates
121
+
122
+ ### Cable Length Considerations
123
+ **Optimal Performance:**
124
+ - Up to 6 feet: Full bandwidth guaranteed
125
+ - 6-15 feet: Full bandwidth with quality cables
126
+ - 15-25 feet: May require active cables for highest resolutions
127
+ - 25+ feet: Active or fiber optic cables recommended
128
+
129
+ ## Installation & Setup
130
+
131
+ ### Basic Connection
132
+ 1. **Power Off Devices**: Turn off both source and display devices
133
+ 2. **Connect Cable**: Insert HDMI connectors fully into ports
134
+ 3. **Power On**: Turn on display first, then source device
135
+ 4. **Select Input**: Use TV/monitor remote to select correct HDMI input
136
+ 5. **Verify Signal**: Check for picture and audio
137
+
138
+ ### Optimizing Picture Quality
139
+ 1. **Display Settings**: Access TV/monitor picture settings
140
+ 2. **HDMI Mode**: Enable "Enhanced" or "Ultra HD Deep Color"
141
+ 3. **HDR Settings**: Enable HDR10, HDR10+, or Dolby Vision
142
+ 4. **Color Space**: Set to BT.2020 for wide color gamut
143
+ 5. **Game Mode**: Enable for gaming sources to reduce lag
144
+
145
+ ### Audio Setup
146
+ 1. **Audio Output**: Set source device to "HDMI" or "Auto"
147
+ 2. **Audio Format**: Select highest quality format supported
148
+ 3. **eARC Setup**: Enable eARC on both TV and soundbar/receiver
149
+ 4. **Channel Configuration**: Set up surround sound speakers
150
+ 5. **Audio Delay**: Adjust if lip-sync issues occur
151
+
152
+ ## Troubleshooting
153
+
154
+ ### No Picture/Black Screen
155
+ **Possible Causes & Solutions:**
156
+ - **Loose Connection**: Ensure cables are fully inserted
157
+ - **Wrong Input**: Verify correct HDMI input selected on display
158
+ - **Resolution Mismatch**: Try lower resolution in source settings
159
+ - **HDCP Issues**: Try powering off both devices for 30 seconds
160
+ - **Cable Failure**: Test with known working cable
161
+
162
+ ### Picture Quality Issues
163
+ **Fuzzy or Pixelated Image:**
164
+ - Check if 4K enhancement mode is enabled on TV
165
+ - Verify source is outputting native resolution
166
+ - Try shorter cable if using long cable
167
+ - Clean connectors with compressed air
168
+
169
+ **Color Issues:**
170
+ - Enable HDR mode on both devices
171
+ - Check color space settings (BT.2020 vs BT.709)
172
+ - Verify cable supports required bandwidth
173
+ - Update device firmware/drivers
174
+
175
+ **Flickering or Intermittent Signal:**
176
+ - Check cable for physical damage
177
+ - Try different HDMI ports
178
+ - Disable VRR temporarily to test
179
+ - Use higher quality cable for long runs
180
+
181
+ ### Audio Problems
182
+ **No Audio:**
183
+ - Check audio output settings on source device
184
+ - Verify HDMI audio is enabled
185
+ - Try different audio format (PCM vs Bitstream)
186
+ - Check if TV speakers are muted
187
+
188
+ **Audio Dropouts:**
189
+ - Ensure cable supports full bandwidth
190
+ - Try disabling advanced audio formats temporarily
191
+ - Check for electromagnetic interference
192
+ - Update device audio drivers
193
+
194
+ **Audio/Video Sync Issues:**
195
+ - Enable audio delay compensation on TV/receiver
196
+ - Try game mode or low latency mode
197
+ - Check if eARC is causing delays
198
+ - Test with basic stereo audio format
199
+
200
+ ### Gaming-Specific Issues
201
+ **High Input Lag:**
202
+ - Enable Game Mode on TV/monitor
203
+ - Verify ALLM is working properly
204
+ - Disable unnecessary picture processing
205
+ - Use HDMI 2.1 cable for latest consoles
206
+
207
+ **Screen Tearing:**
208
+ - Enable VRR on both console and display
209
+ - Check if display supports console's VRR range
210
+ - Try G-Sync/FreeSync compatible mode
211
+ - Update console and display firmware
212
+
213
+ ## Care & Maintenance
214
+
215
+ ### Proper Handling
216
+ - **Connector Care**: Don't force connectors into ports
217
+ - **Cable Management**: Use gentle curves, avoid sharp bends
218
+ - **Strain Relief**: Support cable weight, don't pull on connectors
219
+ - **Storage**: Coil loosely to prevent internal wire damage
220
+
221
+ ### Environmental Considerations
222
+ - **Temperature**: Avoid extreme heat (near fireplaces, heating vents)
223
+ - **Humidity**: Keep away from excessive moisture
224
+ - **UV Exposure**: Protect from direct sunlight for extended periods
225
+ - **Physical Protection**: Route cables away from foot traffic
226
+
227
+ ### Cleaning & Maintenance
228
+ - **Connectors**: Use compressed air to remove dust
229
+ - **Cable Jacket**: Wipe with slightly damp microfiber cloth
230
+ - **Ports**: Clean device HDMI ports regularly
231
+ - **Contact Cleaner**: Use contact cleaner for stubborn corrosion
232
+
233
+ ## Advanced Features
234
+
235
+ ### HDMI 2.1 Gaming Features
236
+ **Variable Refresh Rate (VRR):**
237
+ - Synchronizes display refresh with GPU frame rate
238
+ - Eliminates screen tearing and stuttering
239
+ - Supported range varies by display (typically 40-120Hz)
240
+
241
+ **Auto Low Latency Mode (ALLM):**
242
+ - Automatically enables game mode when gaming signal detected
243
+ - Reduces input lag without manual switching
244
+ - Works with PlayStation 5, Xbox Series X/S
245
+
246
+ **Quick Frame Transport (QFT):**
247
+ - Reduces latency by optimizing frame delivery
248
+ - Most beneficial for competitive gaming
249
+ - Requires compatible source and display
250
+
251
+ ### Professional Features
252
+ **Enhanced Audio Return Channel (eARC):**
253
+ - Full bandwidth audio return from TV to soundbar/receiver
254
+ - Supports uncompressed Dolby Atmos and DTS:X
255
+ - Enables TV as audio hub for multiple sources
256
+
257
+ **Dynamic HDR:**
258
+ - Scene-by-scene or frame-by-frame HDR optimization
259
+ - Supported formats: HDR10+, Dolby Vision
260
+ - Requires compatible content and display
261
+
262
+ ## Technical Specifications
263
+
264
+ ### Electrical Characteristics
265
+ - **Impedance**: 100Ω ±15% differential
266
+ - **Signal Integrity**: Meets HDMI compliance standards
267
+ - **EMI Shielding**: Triple-layer shielding for interference protection
268
+ - **Bandwidth**: Up to 48 Gbps (HDMI 2.1)
269
+
270
+ ### Physical Construction
271
+ - **Conductor**: High-purity copper with silver plating
272
+ - **Dielectric**: Low-loss foam polyethylene
273
+ - **Shielding**: Aluminum foil + tinned copper braid
274
+ - **Jacket**: Durable PVC or braided nylon
275
+
276
+ ### Connector Specifications
277
+ - **Plating**: Gold-plated contacts (minimum 30 micro-inches)
278
+ - **Durability**: Rated for 10,000+ insertion cycles
279
+ - **Retention Force**: Secure connection without excessive force
280
+ - **Contact Resistance**: <20mΩ per contact
281
+
282
+ ## Warranty & Support
283
+
284
+ ### Lifetime Warranty
285
+ All Too Many Cables HDMI cables include:
286
+ - Coverage against manufacturing defects
287
+ - Protection against material failures
288
+ - Performance guarantee under normal use
289
+ - Free replacement for warranted failures
290
+
291
+ ### Customer Support
292
+ - **Technical Support**: Expert guidance on setup and troubleshooting
293
+ - **Compatibility Assistance**: Help choosing the right cable
294
+ - **Warranty Claims**: Fast, hassle-free replacement process
295
+ - **24/7 AI Chat**: Instant support at toomanycables.com
296
+
297
+ ### Contact Information
298
+ - **Phone**: 1-800-TMC-HELP
299
+ - **Email**: support@toomanycables.com
300
+ - **Live Chat**: Available 24/7 on our website
301
+ - **Support Hours**: Monday-Friday 8 AM - 8 PM EST
302
+
303
+ ---
304
+
305
+ *Manual version 3.2 - Updated September 2024*
306
+ *For the latest troubleshooting guides, visit toomanycables.com/support*
knowledge_base/product_manuals/lightning_cables.md ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Lightning Cable Product Manual
2
+
3
+ ## Product Overview
4
+
5
+ Too Many Cables Lightning cables provide reliable charging and data transfer for Apple devices including iPhone, iPad, and iPod.
6
+
7
+ ## Product Specifications
8
+
9
+ ### TMC-LIGHTNING-MFI-6FT
10
+ - **Length**: 6 feet (1.8 meters)
11
+ - **Connector Type**: Lightning to USB-A
12
+ - **Data Transfer**: USB 2.0 speeds up to 480 Mbps
13
+ - **Charging**: Up to 2.4A (12W) fast charging
14
+ - **Certification**: MFi (Made for iPhone/iPad/iPod) certified
15
+ - **Durability**: 10,000+ bend test cycles
16
+ - **Warranty**: 2-year limited warranty
17
+
18
+ ## Compatible Devices
19
+
20
+ ### iPhone Models
21
+ - iPhone 15 series (with adapter)
22
+ - iPhone 14 series and earlier
23
+ - iPhone SE (all generations)
24
+
25
+ ### iPad Models
26
+ - iPad (9th generation and earlier)
27
+ - iPad mini (6th generation and earlier)
28
+ - iPad Air (3rd generation and earlier)
29
+ - iPad Pro 12.9" (2nd generation and earlier)
30
+ - iPad Pro 10.5" and earlier models
31
+
32
+ ### iPod Models
33
+ - iPod touch (7th generation and earlier)
34
+
35
+ ## Usage Instructions
36
+
37
+ ### For Charging
38
+ 1. Connect Lightning end to your Apple device
39
+ 2. Connect USB-A end to charger or computer
40
+ 3. Device should show charging indicator
41
+ 4. Charging speeds vary by device and charger capabilities
42
+
43
+ ### For Data Transfer
44
+ 1. Connect device to computer with cable
45
+ 2. Trust the computer on your iOS device when prompted
46
+ 3. Device should appear in iTunes/Finder
47
+ 4. Transfer speeds depend on file types and device capabilities
48
+
49
+ ## Troubleshooting
50
+
51
+ ### Device Not Charging
52
+ **Symptoms**: No charging indicator, slow charging, intermittent charging
53
+
54
+ **Solutions**:
55
+ - Clean Lightning connector with dry cloth
56
+ - Try different charging adapter
57
+ - Check for debris in device port
58
+ - Ensure cable is fully inserted
59
+ - Try different power outlet
60
+
61
+ ### Device Not Recognized
62
+ **Symptoms**: Computer doesn't detect device, iTunes/Finder doesn't show device
63
+
64
+ **Solutions**:
65
+ - Update iTunes to latest version
66
+ - Try different USB port on computer
67
+ - Restart both devices
68
+ - Check cable for physical damage
69
+ - Ensure device is unlocked and "Trust Computer" is selected
70
+
71
+ ### Slow Data Transfer
72
+ **Solutions**:
73
+ - Use USB 3.0 port if available (cable still USB 2.0 speeds)
74
+ - Close other applications during transfer
75
+ - Transfer smaller batches of files
76
+ - Ensure device has sufficient storage space
77
+
78
+ ## Care and Maintenance
79
+
80
+ ### Daily Use
81
+ - Avoid sharp bends or kinks
82
+ - Don't pull cable by the cord
83
+ - Store in cool, dry place
84
+ - Keep connectors clean and dry
85
+
86
+ ### Storage
87
+ - Coil loosely when storing
88
+ - Avoid extreme temperatures
89
+ - Keep away from sharp objects
90
+ - Store in protective case if available
91
+
92
+ ## Warranty Information
93
+
94
+ ### Coverage
95
+ - 2-year limited warranty from date of purchase
96
+ - Covers manufacturing defects and material failures
97
+ - Does not cover physical damage from misuse
98
+
99
+ ### What's NOT Covered
100
+ - Damage from pets, liquids, or extreme conditions
101
+ - Normal wear and tear
102
+ - Damage from improper use or storage
103
+ - Third-party modifications
104
+
105
+ ## Technical Support
106
+
107
+ For technical assistance:
108
+ - Email: support@toomanycables.com
109
+ - Phone: 1-800-TMC-HELP
110
+ - Live Chat: Available on our website
111
+ - Hours: Monday-Friday 9 AM - 6 PM EST
112
+
113
+ ## Frequently Asked Questions
114
+
115
+ **Q: Is this cable MFi certified?**
116
+ A: Yes, all our Lightning cables are MFi certified by Apple.
117
+
118
+ **Q: Will this work with iPhone 15?**
119
+ A: iPhone 15 uses USB-C. You would need a Lightning to USB-C adapter or our USB-C cables.
120
+
121
+ **Q: Can I use this for fast charging?**
122
+ A: Yes, supports up to 2.4A charging when used with compatible power adapter.
123
+
124
+ **Q: What's the maximum data transfer speed?**
125
+ A: USB 2.0 speeds up to 480 Mbps for data transfer.
knowledge_base/product_manuals/usb_c_audio_adapter.md ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # USB-C to 3.5mm Audio Adapter Product Manual
2
+
3
+ ## Product Overview
4
+
5
+ Too Many Cables USB-C to 3.5mm Audio Adapter provides high-resolution audio output for USB-C devices that lack a traditional headphone jack. Features a premium 32-bit DAC for superior sound quality and compact aluminum housing for durability.
6
+
7
+ ## Product Specifications
8
+
9
+ ### TMC-USBC-AUDIO-32BIT
10
+ - **DAC Chipset**: 32-bit premium audio processing
11
+ - **Sample Rates**: 44.1kHz, 48kHz, 88.2kHz, 96kHz, 176.4kHz, 192kHz
12
+ - **Bit Depth**: 16-bit, 24-bit, 32-bit
13
+ - **Frequency Response**: 20Hz - 40kHz (±0.1dB)
14
+ - **Signal-to-Noise Ratio**: >110dB
15
+ - **Total Harmonic Distortion**: <0.003%
16
+ - **Output Power**: 2 x 15mW @ 32Ω
17
+ - **Connector**: USB-C male to 3.5mm female
18
+ - **Dimensions**: 2.2" x 0.6" x 0.4" (56 x 15 x 10mm)
19
+ - **Weight**: 0.5 oz (15g)
20
+ - **Material**: Premium aluminum alloy housing
21
+ - **Cable**: 4-inch integrated cable
22
+ - **Compatibility**: USB-C devices with audio support
23
+
24
+ ## Audio Performance
25
+
26
+ ### DAC Specifications
27
+ - **Architecture**: Delta-Sigma 32-bit DAC
28
+ - **Dynamic Range**: >110dB
29
+ - **THD+N**: <0.003% at 1kHz
30
+ - **Crosstalk**: <-100dB at 1kHz
31
+ - **Channel Balance**: ±0.1dB
32
+ - **Phase Response**: Linear phase
33
+
34
+ ### Output Characteristics
35
+ - **Maximum Output**: 2V RMS (unloaded)
36
+ - **Output Impedance**: <1 ohm
37
+ - **Load Impedance**: 16Ω to 600Ω (recommended)
38
+ - **Power Output**:
39
+ - 15mW @ 32Ω per channel
40
+ - 10mW @ 150Ω per channel
41
+ - 2mW @ 600Ω per channel
42
+
43
+ ### Supported Audio Formats
44
+ - **PCM**: 16/24/32-bit up to 192kHz
45
+ - **DSD**: Native DSD64, DSD128 (device dependent)
46
+ - **Compressed**: MP3, AAC, FLAC, ALAC, OGG
47
+ - **High-Res**: MQA unfold (software dependent)
48
+
49
+ ## Compatibility Guide
50
+
51
+ ### Compatible Source Devices
52
+
53
+ **Smartphones:**
54
+ - iPhone 15 series and later
55
+ - Samsung Galaxy S20 and later
56
+ - Google Pixel 2 and later
57
+ - OnePlus 6T and later
58
+ - Xiaomi phones with USB-C
59
+ - Huawei phones with USB-C (where available)
60
+
61
+ **Tablets:**
62
+ - iPad Pro (2018 and later)
63
+ - iPad Air (4th generation and later)
64
+ - Samsung Galaxy Tab S series
65
+ - Microsoft Surface Pro with USB-C
66
+
67
+ **Laptops & Computers:**
68
+ - MacBook Pro (2016 and later)
69
+ - MacBook Air (2018 and later)
70
+ - Dell XPS series
71
+ - HP Spectre series
72
+ - Lenovo ThinkPad series
73
+ - Microsoft Surface Laptop series
74
+ - Gaming laptops with USB-C
75
+
76
+ **Other Devices:**
77
+ - Nintendo Switch
78
+ - Steam Deck
79
+ - Android TV boxes
80
+ - USB-C audio interfaces
81
+ - Digital audio players with USB-C
82
+
83
+ ### Compatible Headphones/Earphones
84
+ - **High-Impedance**: Up to 600Ω headphones
85
+ - **Sensitive IEMs**: In-ear monitors (16-32Ω)
86
+ - **Studio Headphones**: Professional monitoring headphones
87
+ - **Consumer Headphones**: Standard 32-300Ω headphones
88
+ - **Earbuds**: Standard and high-end earbuds
89
+
90
+ ## Usage Instructions
91
+
92
+ ### Basic Setup
93
+ 1. Connect adapter's USB-C plug to device
94
+ 2. Connect headphones/earphones to 3.5mm jack
95
+ 3. Audio output automatically switches to adapter
96
+ 4. Adjust volume using device controls
97
+
98
+ ### Audio Quality Optimization
99
+ 1. **High-Res Settings**: Enable high-resolution audio in device settings
100
+ 2. **Sample Rate**: Use native sample rate of audio files when possible
101
+ 3. **Volume**: Set device volume to 75-85% for optimal performance
102
+ 4. **Audio Apps**: Use audiophile apps that support high-res formats
103
+
104
+ ### Device-Specific Setup
105
+
106
+ **Android:**
107
+ 1. Settings → Sound → Audio quality
108
+ 2. Enable "High quality audio" or "Hi-Res audio"
109
+ 3. Select appropriate sample rate if available
110
+ 4. Disable audio processing effects for purest sound
111
+
112
+ **iPhone/iPad:**
113
+ 1. Settings → Music → Audio Quality
114
+ 2. Enable "Lossless" and "Hi-Res Lossless"
115
+ 3. Use Apple Music or compatible apps
116
+ 4. Adapter automatically handles optimal conversion
117
+
118
+ **Windows:**
119
+ 1. Control Panel → Sound → Playbook devices
120
+ 2. Select adapter → Properties → Advanced
121
+ 3. Choose highest quality format available
122
+ 4. Disable audio enhancements for best quality
123
+
124
+ **macOS:**
125
+ 1. System Preferences → Sound → Output
126
+ 2. Select adapter as output device
127
+ 3. Audio MIDI Setup → Configure for high sample rates
128
+ 4. Use high-quality audio applications
129
+
130
+ ## Technical Specifications
131
+
132
+ ### Electrical Requirements
133
+ - **Power Consumption**: <100mW
134
+ - **Supply Voltage**: 5V from USB-C
135
+ - **Current Draw**: <20mA
136
+ - **No External Power**: Bus-powered operation
137
+
138
+ ### Signal Processing
139
+ - **Input**: Digital audio via USB-C
140
+ - **Processing**: 32-bit internal processing
141
+ - **Output**: Analog stereo 3.5mm
142
+ - **Latency**: <10ms digital to analog conversion
143
+
144
+ ### Physical Specifications
145
+ - **Total Length**: 2.2 inches (56mm)
146
+ - **Body Diameter**: 0.6 inches (15mm)
147
+ - **Thickness**: 0.4 inches (10mm)
148
+ - **Weight**: 0.5 oz (15g)
149
+ - **Housing**: CNC machined aluminum
150
+ - **Finish**: Anodized matte black
151
+
152
+ ### Environmental Conditions
153
+ - **Operating Temperature**: 32°F to 104°F (0°C to 40°C)
154
+ - **Storage Temperature**: -4°F to 140°F (-20°C to 60°C)
155
+ - **Humidity**: 10% to 90% RH (non-condensing)
156
+ - **Altitude**: Up to 6,600 feet (2,000m)
157
+
158
+ ## Audio Features
159
+
160
+ ### High-Resolution Audio Support
161
+ - **Studio Quality**: 32-bit/192kHz capable
162
+ - **Low Noise Floor**: >110dB SNR for pristine audio
163
+ - **Wide Bandwidth**: 20Hz-40kHz frequency response
164
+ - **Accurate Reproduction**: <0.003% THD for clean sound
165
+
166
+ ### Advanced Features
167
+ - **Automatic Gain Control**: Prevents clipping and distortion
168
+ - **Pop/Click Suppression**: Eliminates connection artifacts
169
+ - **Power Management**: Intelligent power saving
170
+ - **Universal Compatibility**: Works with all major platforms
171
+
172
+ ## Troubleshooting
173
+
174
+ ### Common Issues
175
+
176
+ **No Audio Output**
177
+ - Verify adapter is fully connected
178
+ - Check device recognizes audio adapter
179
+ - Ensure headphones are properly connected
180
+ - Try different headphones to test adapter
181
+ - Restart device to refresh audio system
182
+
183
+ **Poor Audio Quality**
184
+ - Check audio format settings on device
185
+ - Disable audio processing/effects
186
+ - Verify high-quality audio is enabled
187
+ - Use lossless audio files
188
+ - Check headphone impedance compatibility
189
+
190
+ **Low Volume Output**
191
+ - Increase device volume to 75-85%
192
+ - Check if volume limit is enabled
193
+ - Verify headphone sensitivity rating
194
+ - Try different audio application
195
+ - Check for impedance mismatch
196
+
197
+ **Intermittent Audio**
198
+ - Ensure secure USB-C connection
199
+ - Check for cable/connector damage
200
+ - Clean USB-C port of device
201
+ - Try different USB-C port if available
202
+ - Test with different headphones
203
+
204
+ **Device Not Recognizing Adapter**
205
+ - Restart device with adapter connected
206
+ - Check for driver updates (Windows/Android)
207
+ - Try different USB-C port
208
+ - Verify device supports USB-C audio
209
+ - Contact support if issue persists
210
+
211
+ ### Advanced Troubleshooting
212
+
213
+ **High-Impedance Headphones:**
214
+ - Use headphone amplifier for >300Ω headphones
215
+ - Check power output specifications
216
+ - Consider dedicated headphone amp for best performance
217
+
218
+ **Compatibility Issues:**
219
+ - Verify device supports USB-C audio standard
220
+ - Check if device requires specific drivers
221
+ - Update device firmware/software
222
+ - Try with known compatible device
223
+
224
+ ## Care & Maintenance
225
+
226
+ ### Cleaning Instructions
227
+ - **Disconnect**: Remove from device before cleaning
228
+ - **Dry Cloth**: Use lint-free cloth for housing
229
+ - **Connector Care**: Keep USB-C connector clean and dry
230
+ - **No Liquids**: Avoid moisture in connectors
231
+ - **Storage**: Use provided pouch when not in use
232
+
233
+ ### Preventive Care
234
+ - **Gentle Handling**: Avoid dropping or impact
235
+ - **Cable Protection**: Don't bend cable sharply
236
+ - **Temperature**: Store in moderate temperatures
237
+ - **Moisture**: Keep away from liquids
238
+
239
+ ## What's Included
240
+
241
+ ### Package Contents
242
+ - 1x TMC USB-C to 3.5mm Audio Adapter
243
+ - 1x Premium carrying pouch
244
+ - 1x Quick Start Guide
245
+ - 1x Warranty Registration Card
246
+
247
+ ## Applications
248
+
249
+ ### Audiophile Listening
250
+ - **High-Res Music**: Studio-quality playback
251
+ - **Critical Listening**: Professional audio monitoring
252
+ - **Music Production**: Mobile audio editing
253
+ - **Streaming**: High-quality music streaming services
254
+
255
+ ### Professional Use
256
+ - **Field Recording**: Monitor audio during recording
257
+ - **Broadcasting**: Live audio monitoring
258
+ - **DJ Applications**: Mobile DJ setups
259
+ - **Content Creation**: Podcast and video production
260
+
261
+ ### Gaming & Entertainment
262
+ - **Mobile Gaming**: High-quality game audio
263
+ - **Video Streaming**: Enhanced movie/show audio
264
+ - **Communication**: Clear voice chat audio
265
+ - **Virtual Reality**: Immersive VR audio
266
+
267
+ ## Warranty & Support
268
+
269
+ ### Warranty Coverage
270
+ - **Duration**: 18-month limited warranty
271
+ - **Coverage**: Manufacturing defects and material failures
272
+ - **Exclusions**: Physical damage, misuse, normal wear
273
+
274
+ ### Customer Support
275
+ - **Website**: support.toomanycables.com/audio
276
+ - **Email**: support@toomanycables.com
277
+ - **Phone**: 1-800-TMC-HELP
278
+ - **Live Chat**: Available 24/7 on website
279
+
280
+ ### Warranty Registration
281
+ Register for:
282
+ - Full warranty coverage
283
+ - Product support updates
284
+ - Technical assistance priority
285
+ - Software update notifications
286
+
287
+ ---
288
+
289
+ **Model**: TMC-USBC-AUDIO-32BIT
290
+ **Manual Version**: 1.4
291
+ **Last Updated**: October 2025
292
+ **Document**: TMC-USBC-AUDIO-MANUAL-V1.4
knowledge_base/product_manuals/usb_c_cables.md ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # USB-C Cable Product Manual
2
+
3
+ ## Product Overview
4
+
5
+ Too Many Cables USB-C cables provide high-speed data transfer, fast charging, and video output capabilities for all your USB-C enabled devices. Our premium cables feature gold-plated connectors, high-grade copper conductors, and durable construction backed by our lifetime warranty.
6
+
7
+ ## Product Specifications
8
+
9
+ ### TMC-USBC-100W-6FT (Premium USB-C Cable)
10
+ - **Length**: 6 feet (1.8 meters)
11
+ - **Power Delivery**: Up to 100W (20V/5A)
12
+ - **Data Transfer**: USB 3.2 Gen 2 (10 Gbps)
13
+ - **Video Support**: 4K@60Hz, 1440p@144Hz
14
+ - **Connector**: USB-C to USB-C, reversible
15
+ - **Material**: Braided nylon exterior, gold-plated connectors
16
+ - **Compatibility**: USB-C devices with Power Delivery support
17
+
18
+ ### TMC-USBC-60W-3FT (Standard USB-C Cable)
19
+ - **Length**: 3 feet (0.9 meters)
20
+ - **Power Delivery**: Up to 60W (20V/3A)
21
+ - **Data Transfer**: USB 3.1 Gen 1 (5 Gbps)
22
+ - **Video Support**: 4K@30Hz
23
+ - **Connector**: USB-C to USB-C, reversible
24
+ - **Material**: PVC jacket, gold-plated connectors
25
+ - **Compatibility**: Most USB-C devices
26
+
27
+ ### TMC-USBC-A-FAST (USB-A to USB-C Cable)
28
+ - **Length**: 6 feet (1.8 meters)
29
+ - **Power Delivery**: Up to 18W (9V/2A)
30
+ - **Data Transfer**: USB 3.0 (5 Gbps)
31
+ - **Video Support**: Not supported
32
+ - **Connector**: USB-A to USB-C
33
+ - **Material**: Braided exterior, gold-plated connectors
34
+ - **Compatibility**: USB-A ports to USB-C devices
35
+
36
+ ## Compatibility Guide
37
+
38
+ ### Compatible Devices
39
+ **Smartphones & Tablets:**
40
+ - iPhone 15 series and later
41
+ - Samsung Galaxy S8 and later
42
+ - Google Pixel 2 and later
43
+ - iPad Pro (2018 and later)
44
+ - Most Android devices with USB-C
45
+
46
+ **Laptops & Computers:**
47
+ - MacBook Pro (2016 and later)
48
+ - MacBook Air (2018 and later)
49
+ - Dell XPS series
50
+ - HP Spectre series
51
+ - Lenovo ThinkPad X1 series
52
+ - Surface Pro X and Surface Laptop Studio
53
+
54
+ **Gaming & Accessories:**
55
+ - Nintendo Switch and Switch OLED
56
+ - Steam Deck
57
+ - USB-C headphones and earbuds
58
+ - External drives and hubs
59
+ - Monitors with USB-C input
60
+
61
+ ### Power Delivery Compatibility
62
+ **100W Cables Support:**
63
+ - MacBook Pro 16" (96W)
64
+ - Gaming laptops up to 100W
65
+ - High-power USB-C chargers
66
+ - Power banks with 100W output
67
+
68
+ **60W Cables Support:**
69
+ - MacBook Air (30W)
70
+ - MacBook Pro 13" (61W)
71
+ - Most smartphones and tablets
72
+ - Standard USB-C chargers
73
+
74
+ **18W USB-A Cables Support:**
75
+ - Quick Charge 3.0 devices
76
+ - Standard smartphone charging
77
+ - Tablet charging at reduced speed
78
+
79
+ ## Performance Features
80
+
81
+ ### Fast Charging
82
+ - **Power Delivery 3.0**: Negotiates optimal charging speed
83
+ - **Smart Charging**: Protects devices from overcharging
84
+ - **High Current Support**: Up to 5A for fastest charging
85
+ - **Temperature Management**: Built-in heat dissipation
86
+
87
+ ### High-Speed Data Transfer
88
+ - **USB 3.2 Gen 2**: Up to 10 Gbps transfer speeds
89
+ - **Backward Compatible**: Works with USB 2.0 and 3.0
90
+ - **Low Latency**: Optimized for gaming and real-time applications
91
+ - **Error Correction**: Built-in data integrity protection
92
+
93
+ ### Video Output
94
+ - **4K Resolution**: Support for 4K@60Hz displays
95
+ - **HDR Support**: High Dynamic Range video transmission
96
+ - **Multi-Stream**: Supports multiple displays via hubs
97
+ - **Audio Included**: Digital audio transmission with video
98
+
99
+ ## Installation & Setup
100
+
101
+ ### Basic Connection
102
+ 1. **Identify Ports**: Locate USB-C ports on both devices
103
+ 2. **Insert Cable**: USB-C connectors are reversible - either way works
104
+ 3. **Verify Connection**: Look for charging indicator or connection notification
105
+ 4. **Test Functionality**: Try data transfer or video output as needed
106
+
107
+ ### For Charging
108
+ 1. Connect cable to power adapter and device
109
+ 2. Device should show charging indicator
110
+ 3. For fast charging, use compatible PD charger
111
+ 4. Charging speeds vary by device and charger capabilities
112
+
113
+ ### For Data Transfer
114
+ 1. Connect devices with cable
115
+ 2. On phone/tablet: Select "File Transfer" or "MTP" mode
116
+ 3. Devices should appear in file explorer
117
+ 4. Transfer speeds depend on both devices' capabilities
118
+
119
+ ### For Video Output
120
+ 1. Connect device to monitor/TV with USB-C input
121
+ 2. Device may automatically detect display
122
+ 3. For manual setup: Go to display settings
123
+ 4. Select appropriate resolution and refresh rate
124
+
125
+ ## Troubleshooting
126
+
127
+ ### Charging Issues
128
+ **Problem**: Device not charging
129
+ **Solutions**:
130
+ - Check that both connectors are fully inserted
131
+ - Try a different USB-C port if available
132
+ - Verify charger is working with another device
133
+ - Clean connectors with compressed air
134
+ - Try different orientation (flip cable connectors)
135
+
136
+ **Problem**: Slow charging
137
+ **Solutions**:
138
+ - Use original or certified high-wattage charger
139
+ - Check if device supports fast charging
140
+ - Close power-hungry apps while charging
141
+ - Ensure cable supports device's charging requirements
142
+
143
+ ### Data Transfer Issues
144
+ **Problem**: Device not recognized
145
+ **Solutions**:
146
+ - Select correct USB mode on phone/tablet
147
+ - Install device drivers if on Windows
148
+ - Try different USB-C port
149
+ - Restart both devices
150
+ - Check cable for physical damage
151
+
152
+ **Problem**: Slow transfer speeds
153
+ **Solutions**:
154
+ - Verify both devices support USB 3.0+
155
+ - Close other applications during transfer
156
+ - Use USB-C port directly, not through hub
157
+ - Check cable specifications match requirements
158
+
159
+ ### Video Output Issues
160
+ **Problem**: No video signal
161
+ **Solutions**:
162
+ - Verify device supports video output over USB-C
163
+ - Check monitor/TV input is set to correct USB-C port
164
+ - Try different resolution in display settings
165
+ - Ensure cable supports video (not all USB-C cables do)
166
+ - Update device graphics drivers
167
+
168
+ **Problem**: Poor video quality
169
+ **Solutions**:
170
+ - Check maximum resolution supported by cable
171
+ - Verify monitor's native resolution settings
172
+ - Adjust refresh rate in display settings
173
+ - Use shorter cable for better signal integrity
174
+
175
+ ## Care & Maintenance
176
+
177
+ ### Proper Handling
178
+ - **Gentle Insertion**: Don't force connectors into ports
179
+ - **Avoid Bending**: Don't bend cable at sharp angles near connectors
180
+ - **Strain Relief**: Use built-in strain relief, don't pull on cable
181
+ - **Storage**: Coil loosely when storing, avoid tight knots
182
+
183
+ ### Cleaning
184
+ - **Connectors**: Use compressed air to remove dust and debris
185
+ - **Cable**: Wipe with slightly damp cloth, avoid harsh chemicals
186
+ - **Ports**: Clean device ports regularly with compressed air
187
+ - **Contacts**: Use isopropyl alcohol on cotton swab if needed
188
+
189
+ ### Environmental Protection
190
+ - **Temperature**: Avoid extreme heat or cold storage
191
+ - **Moisture**: Keep dry, avoid liquid exposure
192
+ - **Sunlight**: Don't leave in direct sunlight for extended periods
193
+ - **Stress**: Avoid pinching, crushing, or excessive bending
194
+
195
+ ## Technical Specifications
196
+
197
+ ### Electrical Ratings
198
+ - **Voltage Range**: 5V to 20V (depending on model)
199
+ - **Current Rating**: Up to 5A (100W models)
200
+ - **Resistance**: <50mΩ for optimal power delivery
201
+ - **Insulation**: 2000V AC dielectric strength
202
+
203
+ ### Data Specifications
204
+ - **Signal Integrity**: Meets USB-IF compliance standards
205
+ - **EMI/RFI**: Shielded construction reduces interference
206
+ - **Crosstalk**: Minimized through proper wire spacing
207
+ - **Impedance**: 90Ω ±15% differential impedance
208
+
209
+ ### Physical Specifications
210
+ - **Connector**: USB Type-C (USB-C) certified
211
+ - **Housing**: Durable plastic with metal shell
212
+ - **Cable Gauge**: 28/24 AWG (data/power)
213
+ - **Bend Radius**: Minimum 10x cable diameter
214
+
215
+ ## Warranty Information
216
+
217
+ ### Lifetime Warranty Coverage
218
+ All Too Many Cables USB-C cables are covered by our comprehensive lifetime warranty against:
219
+ - Manufacturing defects
220
+ - Material failures
221
+ - Performance degradation under normal use
222
+ - Connector wear from regular insertion/removal
223
+
224
+ ### Warranty Exclusions
225
+ - Physical damage from misuse or accidents
226
+ - Damage from liquids, pets, or extreme conditions
227
+ - Commercial/industrial use beyond specifications
228
+ - Modification or repair attempts
229
+
230
+ ### Claim Process
231
+ 1. Contact customer service with order information
232
+ 2. Describe the issue and troubleshooting attempted
233
+ 3. Receive replacement authorization if covered
234
+ 4. Replacement shipped same day at no cost
235
+ 5. No need to return defective cable unless requested
236
+
237
+ ## Customer Support
238
+
239
+ For technical support, compatibility questions, or warranty claims:
240
+
241
+ - **AI Chat**: Available 24/7 on our website
242
+ - **Email**: support@toomanycables.com
243
+ - **Phone**: 1-800-TMC-HELP
244
+ - **Hours**: Monday-Friday 8 AM - 8 PM EST
245
+
246
+ ## Safety Information
247
+
248
+ ### Important Safety Warnings
249
+ - Use only with compatible devices and chargers
250
+ - Do not exceed maximum power ratings
251
+ - Discontinue use if cable becomes hot during operation
252
+ - Keep away from heat sources and sharp objects
253
+ - Do not use damaged cables
254
+
255
+ ### Regulatory Compliance
256
+ - FCC Part 15 Class B (EMI compliance)
257
+ - USB-IF certification
258
+ - RoHS compliant (lead-free)
259
+ - UL recognized components
260
+
261
+ ---
262
+
263
+ *Manual version 2.1 - Updated September 2024*
264
+ *For the latest version, visit toomanycables.com/support*
knowledge_base/product_manuals/usb_c_hdmi_adapter.md ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # USB-C to HDMI Adapter Product Manual
2
+
3
+ ## Product Overview
4
+
5
+ Too Many Cables USB-C to HDMI Adapter provides a simple plug-and-play solution for connecting USB-C enabled devices to HDMI displays, monitors, and TVs. Ultra-compact design delivers 4K video output with high-quality digital audio transmission.
6
+
7
+ ## Product Specifications
8
+
9
+ ### TMC-USBC-HDMI-4K
10
+ - **Video Output**: Up to 4K@60Hz (3840x2160)
11
+ - **Audio Support**: Multi-channel digital audio pass-through
12
+ - **Connector Type**: USB-C male to HDMI female
13
+ - **Compatibility**: USB-C devices with DisplayPort Alt Mode
14
+ - **Dimensions**: 2.4" x 0.8" x 0.4" (61 x 20 x 10mm)
15
+ - **Weight**: 0.7 oz (20g)
16
+ - **Material**: Aluminum alloy housing with gold-plated connectors
17
+ - **Cable Length**: Built-in 4-inch cable
18
+ - **Power**: Bus-powered (no external power required)
19
+ - **Operating Temperature**: 32°F to 104°F (0°C to 40°C)
20
+
21
+ ## Video Output Specifications
22
+
23
+ ### Supported Resolutions
24
+ - **4K Ultra HD**: 3840x2160 @ 60Hz, 30Hz
25
+ - **1440p QHD**: 2560x1440 @ 60Hz, 144Hz
26
+ - **1080p Full HD**: 1920x1080 @ 60Hz, 120Hz, 144Hz
27
+ - **1080i**: 1920x1080i @ 60Hz
28
+ - **720p HD**: 1280x720 @ 60Hz
29
+ - **Legacy Formats**: 1024x768, 800x600, 640x480
30
+
31
+ ### Color Support
32
+ - **Color Depth**: 8-bit, 10-bit, 12-bit
33
+ - **Color Space**: RGB, YUV 4:4:4, YUV 4:2:2, YUV 4:2:0
34
+ - **HDR Support**: HDR10 (device dependent)
35
+ - **Color Standards**: sRGB, Adobe RGB, DCI-P3
36
+
37
+ ### Audio Specifications
38
+ - **Audio Formats**: PCM, Dolby Digital, DTS
39
+ - **Sample Rates**: 32kHz, 44.1kHz, 48kHz, 96kHz
40
+ - **Bit Depth**: 16-bit, 24-bit
41
+ - **Channels**: Stereo, 5.1, 7.1 surround sound
42
+ - **Audio Delay**: <40ms latency
43
+
44
+ ## Compatibility Guide
45
+
46
+ ### Compatible Source Devices
47
+
48
+ **Laptops:**
49
+ - MacBook Pro (2016 and later)
50
+ - MacBook Air (2018 and later)
51
+ - Dell XPS 13/15/17 series
52
+ - HP Spectre x360 series
53
+ - Lenovo ThinkPad X1 series
54
+ - Microsoft Surface Laptop series
55
+ - ASUS ZenBook series
56
+ - Most Windows laptops with USB-C/Thunderbolt
57
+
58
+ **Tablets:**
59
+ - iPad Pro (2018 and later)
60
+ - iPad Air (4th generation and later)
61
+ - Samsung Galaxy Tab S series
62
+ - Microsoft Surface Pro (USB-C models)
63
+
64
+ **Smartphones:**
65
+ - Samsung Galaxy S8 and later
66
+ - Google Pixel 2 and later
67
+ - OnePlus 6 and later
68
+ - Huawei P20 and later (where available)
69
+ - Motorola Moto series with USB-C
70
+
71
+ **Other Devices:**
72
+ - Nintendo Switch
73
+ - Steam Deck
74
+ - Chrome OS devices
75
+ - Android TV boxes with USB-C
76
+
77
+ ### Display Compatibility
78
+ - **TVs**: All HDMI-equipped TVs (HD, 4K, 8K)
79
+ - **Monitors**: Computer monitors with HDMI input
80
+ - **Projectors**: HDMI-equipped projectors
81
+ - **Capture Devices**: HDMI capture cards and recorders
82
+
83
+ ## Usage Instructions
84
+
85
+ ### Basic Connection
86
+ 1. Connect adapter's USB-C plug to your device
87
+ 2. Connect HDMI cable from adapter to display
88
+ 3. Display should automatically detect signal
89
+ 4. Adjust display settings if needed
90
+
91
+ ### Display Configuration
92
+
93
+ **Windows:**
94
+ 1. Right-click desktop → Display Settings
95
+ 2. Choose "Extend" or "Duplicate" display
96
+ 3. Select resolution and refresh rate
97
+ 4. Apply settings
98
+
99
+ **macOS:**
100
+ 1. System Preferences → Displays
101
+ 2. Choose "Mirror" or "Extend" desktop
102
+ 3. Select optimal resolution
103
+ 4. Adjust color profile if needed
104
+
105
+ **Android/Chrome OS:**
106
+ 1. Settings → Display
107
+ 2. Select "Cast screen" or "Screen mirroring"
108
+ 3. Choose display mode (mirror/extend)
109
+ 4. Configure resolution settings
110
+
111
+ ## Performance Optimization
112
+
113
+ ### Maximum Quality Settings
114
+ - **4K Output**: Use high-quality HDMI cables rated for 4K@60Hz
115
+ - **Refresh Rate**: Set to highest supported by both device and display
116
+ - **Color Settings**: Enable HDR if supported by both devices
117
+ - **Audio Quality**: Use highest available audio format
118
+
119
+ ### Troubleshooting Performance
120
+ - **Update Drivers**: Ensure graphics drivers are current
121
+ - **Cable Quality**: Use HDMI 2.0 or higher rated cables
122
+ - **Power Settings**: Disable power saving for USB ports
123
+ - **Resolution**: Try lower resolution if experiencing issues
124
+
125
+ ## Technical Specifications
126
+
127
+ ### Electrical Requirements
128
+ - **Power Consumption**: <2W
129
+ - **Power Source**: USB-C bus power
130
+ - **Current Draw**: <400mA @ 5V
131
+ - **No External Power**: Required
132
+
133
+ ### Signal Specifications
134
+ - **HDMI Version**: HDMI 2.0 compatible
135
+ - **Bandwidth**: Up to 18 Gbps
136
+ - **HDCP Support**: HDCP 2.2, HDCP 1.4
137
+ - **Signal Type**: Digital video and audio
138
+
139
+ ### Physical Specifications
140
+ - **Length**: 2.4 inches (61mm) including cable
141
+ - **Width**: 0.8 inches (20mm)
142
+ - **Thickness**: 0.4 inches (10mm)
143
+ - **Weight**: 0.7 oz (20g)
144
+ - **Housing**: Aluminum alloy
145
+ - **Connectors**: Gold-plated for corrosion resistance
146
+
147
+ ### Environmental Conditions
148
+ - **Operating Temperature**: 32°F to 104°F (0°C to 40°C)
149
+ - **Storage Temperature**: -4°F to 140°F (-20°C to 60°C)
150
+ - **Humidity**: 10% to 95% RH (non-condensing)
151
+ - **Altitude**: Up to 6,600 feet (2,000m)
152
+
153
+ ## Troubleshooting
154
+
155
+ ### Common Issues
156
+
157
+ **No Display Output**
158
+ - Verify device supports video output via USB-C
159
+ - Check HDMI cable connection
160
+ - Try different HDMI cable
161
+ - Restart source device
162
+ - Check display input selection
163
+
164
+ **Poor Video Quality**
165
+ - Use high-quality HDMI cable
166
+ - Check resolution settings
167
+ - Update graphics drivers
168
+ - Verify cable supports desired resolution
169
+ - Try different display if available
170
+
171
+ **No Audio Output**
172
+ - Check audio output settings on device
173
+ - Verify HDMI audio is enabled
174
+ - Try different audio format
175
+ - Check display audio settings
176
+ - Update audio drivers
177
+
178
+ **Intermittent Connection**
179
+ - Check USB-C connection is secure
180
+ - Try different USB-C port
181
+ - Inspect cable for damage
182
+ - Clean connectors
183
+ - Test with different HDMI cable
184
+
185
+ **4K Resolution Issues**
186
+ - Verify device supports 4K output
187
+ - Use HDMI 2.0 or higher cable
188
+ - Check display 4K compatibility
189
+ - Try 4K@30Hz instead of 60Hz
190
+ - Update device firmware
191
+
192
+ ### Advanced Troubleshooting
193
+
194
+ **Driver Issues:**
195
+ - Download latest graphics drivers
196
+ - Restart device after driver installation
197
+ - Check Windows Update for driver updates
198
+
199
+ **Compatibility Problems:**
200
+ - Verify USB-C port supports video (some are charging only)
201
+ - Check if device requires specific adapter protocols
202
+ - Try adapter with known compatible device
203
+
204
+ **Performance Optimization:**
205
+ - Close unnecessary applications
206
+ - Adjust power settings for performance
207
+ - Check thermal throttling
208
+ - Monitor CPU/GPU usage
209
+
210
+ ## Care & Maintenance
211
+
212
+ ### Cleaning Instructions
213
+ - **Disconnect**: Remove from devices before cleaning
214
+ - **Dry Cloth**: Use lint-free cloth for exterior
215
+ - **Connector Care**: Keep connectors clean and dry
216
+ - **No Liquids**: Avoid moisture in connectors
217
+
218
+ ### Storage Recommendations
219
+ - **Protective Case**: Store in provided pouch when not in use
220
+ - **Avoid Bending**: Don't stress the built-in cable
221
+ - **Temperature**: Store in cool, dry location
222
+ - **Avoid Pressure**: Don't place heavy objects on adapter
223
+
224
+ ## What's Included
225
+
226
+ ### Package Contents
227
+ - 1x TMC USB-C to HDMI Adapter
228
+ - 1x Protective carrying pouch
229
+ - 1x Quick Start Guide
230
+ - 1x Warranty Registration Card
231
+
232
+ ## Warranty & Support
233
+
234
+ ### Warranty Coverage
235
+ - **Duration**: 18-month limited warranty
236
+ - **Coverage**: Manufacturing defects and material failures
237
+ - **Exclusions**: Physical damage, misuse, normal wear
238
+
239
+ ### Customer Support
240
+ - **Website**: support.toomanycables.com/adapters
241
+ - **Email**: support@toomanycables.com
242
+ - **Phone**: 1-800-TMC-HELP
243
+ - **Live Chat**: Available 24/7 on website
244
+
245
+ ### Warranty Registration
246
+ Register within 30 days for:
247
+ - Full warranty coverage
248
+ - Product support notifications
249
+ - Technical assistance priority
250
+
251
+ ---
252
+
253
+ **Model**: TMC-USBC-HDMI-4K
254
+ **Manual Version**: 1.3
255
+ **Last Updated**: October 2025
256
+ **Document**: TMC-HDMI-ADAPTER-MANUAL-V1.3
knowledge_base/product_manuals/usb_c_hub_adapter.md ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # USB-C Hub Adapter Product Manual
2
+
3
+ ## Product Overview
4
+
5
+ Too Many Cables 7-in-1 USB-C Hub Adapter expands a single USB-C port into multiple connectivity options including 4K HDMI, USB-A ports, SD card slots, Ethernet, and USB-C Power Delivery pass-through. Perfect for laptops, tablets, and phones with USB-C ports.
6
+
7
+ ## Product Specifications
8
+
9
+ ### TMC-USBC-HUB-7IN1
10
+ - **Port Configuration**:
11
+ - 1x HDMI 2.0 port (4K@60Hz)
12
+ - 3x USB-A 3.0 ports (5 Gbps)
13
+ - 1x USB-C PD port (100W pass-through)
14
+ - 1x SD card slot (UHS-I)
15
+ - 1x MicroSD card slot (UHS-I)
16
+ - 1x Gigabit Ethernet port (10/100/1000 Mbps)
17
+ - **Dimensions**: 4.7" x 1.4" x 0.6" (120 x 35 x 15mm)
18
+ - **Weight**: 2.1 oz (60g)
19
+ - **Material**: Premium aluminum alloy housing
20
+ - **Cable**: 6-inch integrated USB-C cable
21
+ - **LED Indicators**: Power and data activity LEDs
22
+ - **Operating Temperature**: 32°F to 104°F (0°C to 40°C)
23
+ - **Certifications**: CE, FCC, RoHS compliant
24
+
25
+ ## Detailed Port Specifications
26
+
27
+ ### HDMI 2.0 Port
28
+ - **Maximum Resolution**: 4K@60Hz (3840x2160)
29
+ - **Supported Formats**: 1080p@120Hz, 1440p@60Hz, 4K@30Hz, 4K@60Hz
30
+ - **Color Depth**: 8-bit, 10-bit, 12-bit
31
+ - **Audio Support**: Multi-channel audio pass-through
32
+ - **HDR Support**: HDR10, HDR10+
33
+ - **Compatibility**: All HDMI displays and TVs
34
+
35
+ ### USB-A 3.0 Ports (3x)
36
+ - **Data Transfer**: Up to 5 Gbps (USB 3.0/3.1 Gen 1)
37
+ - **Power Output**: 5V/0.9A per port (4.5W total across all USB-A ports)
38
+ - **Compatibility**: USB 3.0, 2.0, 1.1 devices
39
+ - **Hot Plug**: Support for hot-swappable devices
40
+ - **Backwards Compatible**: Works with all USB devices
41
+
42
+ ### USB-C PD Pass-Through Port
43
+ - **Power Delivery**: Up to 100W pass-through charging
44
+ - **Data Transfer**: USB 3.0 speeds (5 Gbps)
45
+ - **Compatibility**: USB-C PD chargers and devices
46
+ - **Charging**: Allows laptop charging while using hub
47
+ - **Power Efficiency**: >85% power pass-through efficiency
48
+
49
+ ### SD Card Slots
50
+ - **SD Card Slot**: UHS-I, up to 104 MB/s
51
+ - **MicroSD Slot**: UHS-I, up to 104 MB/s
52
+ - **Supported Formats**: SD, SDHC, SDXC (up to 2TB)
53
+ - **Simultaneous Access**: Both slots can be used at same time
54
+ - **Hot Swap**: Cards can be inserted/removed while hub is connected
55
+
56
+ ### Gigabit Ethernet Port
57
+ - **Speed**: 10/100/1000 Mbps auto-negotiation
58
+ - **Connector**: RJ45 standard Ethernet
59
+ - **LED Indicators**: Link/Activity status
60
+ - **Compatibility**: All standard Ethernet networks
61
+ - **Driver**: Plug-and-play, no drivers needed
62
+
63
+ ## Compatibility Guide
64
+
65
+ ### Compatible Laptops
66
+ **MacBook Series:**
67
+ - MacBook Pro 13" (2016 and later)
68
+ - MacBook Pro 14" and 16" (M1/M2/M3)
69
+ - MacBook Air 13" (2018 and later)
70
+ - MacBook Air 15" (M2/M3)
71
+
72
+ **Windows Laptops:**
73
+ - Dell XPS 13/15/17 series
74
+ - HP Spectre x360 series
75
+ - HP EliteBook series
76
+ - Lenovo ThinkPad X1 Carbon
77
+ - Lenovo Yoga series
78
+ - Microsoft Surface Laptop series
79
+ - ASUS ZenBook series
80
+
81
+ **Chromebooks:**
82
+ - Google Pixelbook
83
+ - Samsung Galaxy Chromebook
84
+ - HP Chromebook x360
85
+ - Most Chromebooks with USB-C
86
+
87
+ ### Compatible Tablets
88
+ - iPad Pro (2018 and later)
89
+ - iPad Air (4th generation and later)
90
+ - Samsung Galaxy Tab S series
91
+ - Microsoft Surface Pro (with USB-C)
92
+
93
+ ### Compatible Phones
94
+ - Samsung Galaxy S20 and later
95
+ - Google Pixel 3a and later (with USB-C)
96
+ - OnePlus 7 and later
97
+ - Note: Phone compatibility may vary by model
98
+
99
+ ## Usage Instructions
100
+
101
+ ### Initial Setup
102
+ 1. Connect hub's USB-C cable to your device's USB-C port
103
+ 2. Hub powers on automatically (LED indicator lights up)
104
+ 3. Connect desired peripherals to hub ports
105
+ 4. Devices should be recognized automatically
106
+
107
+ ### HDMI Display Connection
108
+ 1. Connect HDMI cable from hub to monitor/TV
109
+ 2. Display should be detected automatically
110
+ 3. Adjust display settings in system preferences if needed
111
+ 4. Supports mirroring and extended desktop modes
112
+
113
+ ### Power Delivery Usage
114
+ 1. Connect USB-C charger to hub's PD port
115
+ 2. Hub passes power to connected laptop/device
116
+ 3. Device charges while hub functions normally
117
+ 4. Use original charger for best performance
118
+
119
+ ### Ethernet Connection
120
+ 1. Connect Ethernet cable to hub's RJ45 port
121
+ 2. Network connection established automatically
122
+ 3. LED shows link status and activity
123
+ 4. Provides stable wired internet connection
124
+
125
+ ## Performance Optimization
126
+
127
+ ### Maximum Performance Tips
128
+ - **Use Quality Cables**: High-quality HDMI and USB cables for best results
129
+ - **Adequate Power**: Use appropriate wattage charger for your device
130
+ - **Heat Management**: Ensure good ventilation around hub
131
+ - **Update Drivers**: Keep device drivers updated for optimal compatibility
132
+
133
+ ### Data Transfer Optimization
134
+ - **USB 3.0 Devices**: Use USB 3.0 storage devices for maximum speed
135
+ - **SD Card Performance**: Use high-speed SD cards (Class 10 or UHS-I)
136
+ - **Ethernet Speed**: Use Cat 6 cables for Gigabit speeds
137
+ - **Avoid Overloading**: Don't exceed total power budget
138
+
139
+ ## Technical Specifications
140
+
141
+ ### Power Requirements
142
+ - **Input Power**: 5V from USB-C host device
143
+ - **Power Consumption**: 2W (hub operation)
144
+ - **USB-A Power Budget**: 4.5W total across all USB-A ports
145
+ - **PD Pass-Through**: Up to 100W (minus 15W hub overhead)
146
+
147
+ ### Data Transfer Rates
148
+ - **USB-A Ports**: 5 Gbps each (shared bandwidth)
149
+ - **USB-C Port**: 5 Gbps
150
+ - **SD Cards**: Up to 104 MB/s (UHS-I)
151
+ - **Ethernet**: Up to 1000 Mbps
152
+ - **HDMI**: Up to 18 Gbps bandwidth
153
+
154
+ ### Environmental Specifications
155
+ - **Operating Temperature**: 32°F to 104°F (0°C to 40°C)
156
+ - **Storage Temperature**: -4°F to 140°F (-20°C to 60°C)
157
+ - **Humidity**: 10% to 90% RH (non-condensing)
158
+ - **Altitude**: Up to 6,600 feet (2,000m)
159
+
160
+ ## Troubleshooting
161
+
162
+ ### Common Issues
163
+
164
+ **Hub Not Recognized**
165
+ - Check USB-C connection is secure
166
+ - Try different USB-C port on device
167
+ - Restart connected device
168
+ - Verify device supports USB-C data
169
+
170
+ **HDMI Display Not Working**
171
+ - Check HDMI cable connections
172
+ - Try different HDMI cable
173
+ - Verify display supports resolution
174
+ - Update graphics drivers
175
+
176
+ **USB Devices Not Working**
177
+ - Check USB device compatibility
178
+ - Try connecting device directly to test
179
+ - Verify power requirements
180
+ - Use powered USB hub if needed
181
+
182
+ **Ethernet Not Connecting**
183
+ - Check Ethernet cable connection
184
+ - Verify network settings
185
+ - Try different Ethernet cable
186
+ - Check router/switch status
187
+
188
+ **Charging Not Working**
189
+ - Verify charger wattage is adequate
190
+ - Check USB-C PD charger compatibility
191
+ - Try original device charger
192
+ - Ensure hub PD port is used
193
+
194
+ ### Advanced Troubleshooting
195
+ - **Driver Updates**: Install latest USB-C and graphics drivers
196
+ - **Power Management**: Disable USB selective suspend in power settings
197
+ - **Display Settings**: Check resolution and refresh rate settings
198
+ - **Network Configuration**: Verify Ethernet adapter settings
199
+
200
+ ## Safety Information
201
+
202
+ ### Important Safety Notes
203
+ - **Heat Dissipation**: Hub may become warm during use - this is normal
204
+ - **Water Protection**: Keep hub away from liquids
205
+ - **Ventilation**: Don't block ventilation holes
206
+ - **Cable Stress**: Avoid bending USB-C cable excessively
207
+
208
+ ### Certifications
209
+ - **CE Marking**: European Conformity
210
+ - **FCC Certified**: Electromagnetic compatibility
211
+ - **RoHS Compliant**: Restriction of hazardous substances
212
+
213
+ ## What's Included
214
+
215
+ ### Package Contents
216
+ - 1x TMC 7-in-1 USB-C Hub
217
+ - 1x Quick Start Guide
218
+ - 1x Warranty Registration Card
219
+ - 1x Premium carrying pouch
220
+
221
+ ## Warranty & Support
222
+
223
+ ### Warranty Coverage
224
+ - **Duration**: 2-year limited warranty
225
+ - **Coverage**: Manufacturing defects and material failures
226
+ - **Exclusions**: Physical damage, misuse, normal wear
227
+
228
+ ### Customer Support
229
+ - **Website**: support.toomanycables.com/hub
230
+ - **Email**: support@toomanycables.com
231
+ - **Phone**: 1-800-TMC-HELP
232
+ - **Live Chat**: Available 24/7 on website
233
+ - **Support Hours**: Monday-Friday 8AM-8PM EST
234
+
235
+ ### Warranty Registration
236
+ Register your product for:
237
+ - Full warranty coverage
238
+ - Product update notifications
239
+ - Priority technical support
240
+
241
+ ---
242
+
243
+ **Model**: TMC-USBC-HUB-7IN1
244
+ **Manual Version**: 1.6
245
+ **Last Updated**: October 2025
246
+ **Document**: TMC-HUB-MANUAL-V1.6
knowledge_base/product_manuals/wireless_charging_pad.md ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Wireless Charging Pad Product Manual
2
+
3
+ ## Product Overview
4
+
5
+ Too Many Cables Wireless Charging Pad delivers fast 15W wireless charging for Qi-enabled devices with intelligent charging control, LED status indicators, and a premium non-slip design for safe and efficient wireless power delivery.
6
+
7
+ ## Product Specifications
8
+
9
+ ### TMC-WIRELESS-15W-QI
10
+ - **Maximum Output**: 15W (fast wireless charging)
11
+ - **Charging Standards**: Qi 1.2.4 (EPP), Qi 1.1 (BPP)
12
+ - **Charging Modes**:
13
+ - 15W (compatible phones in fast mode)
14
+ - 10W (Samsung fast charging)
15
+ - 7.5W (iPhone fast charging)
16
+ - 5W (standard Qi charging)
17
+ - **Input**: USB-C, 5V/3A, 9V/2A (QC 3.0/PD compatible)
18
+ - **Dimensions**: 4.3" diameter x 0.4" height (110mm x 10mm)
19
+ - **Weight**: 4.2 oz (120g)
20
+ - **Material**: Premium aluminum top, ABS plastic base
21
+ - **LED Indicator**: Multi-color status LED
22
+ - **Safety Features**: Over-temperature, over-voltage, foreign object detection
23
+ - **Certifications**: Qi Certified, FCC, CE, RoHS
24
+
25
+ ## Compatibility Guide
26
+
27
+ ### Fast Charging Compatible (15W)
28
+ **Android Phones:**
29
+ - Samsung Galaxy S21/S22/S23/S24 series
30
+ - Google Pixel 4 and later
31
+ - OnePlus 8 and later
32
+ - LG V30 and later
33
+ - Sony Xperia 1 II and later
34
+
35
+ ### iPhone Fast Charging (7.5W)
36
+ - iPhone 8 and later
37
+ - iPhone SE (2nd/3rd generation)
38
+ - iPhone X/XR/XS series
39
+ - iPhone 11/12/13/14/15 series
40
+
41
+ ### Standard Charging (5W)
42
+ - Most Qi-enabled devices
43
+ - Older wireless charging phones
44
+ - AirPods with wireless charging case
45
+ - Samsung Galaxy Buds series
46
+
47
+ ### Case Compatibility
48
+ - **Compatible**: Cases up to 5mm thick (non-metal)
49
+ - **Remove Cases**: Metal cases, magnetic mounts, credit cards
50
+ - **Recommended**: Official phone cases, thin plastic/silicone cases
51
+
52
+ ## Usage Instructions
53
+
54
+ ### Initial Setup
55
+ 1. Connect USB-C cable to charging pad
56
+ 2. Connect other end to QC 3.0 or PD wall adapter (included)
57
+ 3. Place charging pad on flat, stable surface
58
+ 4. LED should show solid blue (ready to charge)
59
+
60
+ ### Charging Your Device
61
+ 1. Remove metal cases and objects from phone
62
+ 2. Place device center of charging pad
63
+ 3. LED changes to indicate charging status
64
+ 4. Charging begins automatically
65
+ 5. LED shows green when fully charged
66
+
67
+ ### Optimal Positioning
68
+ - **Center Alignment**: Place device center of pad for best efficiency
69
+ - **Portrait/Landscape**: Both orientations supported
70
+ - **Multiple Devices**: Charge one device at a time for best performance
71
+
72
+ ## LED Status Indicators
73
+
74
+ ### LED Color Meanings
75
+ - **Solid Blue**: Ready to charge, no device detected
76
+ - **Solid Green**: Device charging normally
77
+ - **Blinking Green**: Device fully charged
78
+ - **Solid Red**: Error condition (foreign object, overheating)
79
+ - **Blinking Red**: Device not compatible or misaligned
80
+ - **Purple**: Fast charging mode active
81
+
82
+ ### Troubleshooting LED Codes
83
+ - **No LED**: Check power connection and adapter
84
+ - **Red Solid**: Remove foreign objects, check alignment
85
+ - **Red Blinking**: Reposition device, remove thick case
86
+
87
+ ## Safety Features
88
+
89
+ ### Protection Systems
90
+ - **Foreign Object Detection (FOD)**: Stops charging when metal objects detected
91
+ - **Temperature Control**: Automatic power reduction if overheating
92
+ - **Over-Voltage Protection**: Protects against power surges
93
+ - **Over-Current Protection**: Prevents excessive current draw
94
+ - **Short-Circuit Protection**: Immediate shutdown on electrical faults
95
+
96
+ ### Thermal Management
97
+ - **Heat Dissipation**: Aluminum surface for efficient heat transfer
98
+ - **Temperature Monitoring**: Real-time thermal sensing
99
+ - **Cooling Periods**: Automatic charging pauses if temperature exceeds limits
100
+ - **Ventilation**: Bottom air channels for passive cooling
101
+
102
+ ## Performance Optimization
103
+
104
+ ### Maximum Charging Speed
105
+ - **Use Included Adapter**: QC 3.0 18W adapter for best performance
106
+ - **Remove Thick Cases**: Cases over 5mm may reduce charging speed
107
+ - **Proper Alignment**: Center device on pad for optimal efficiency
108
+ - **Room Temperature**: Avoid direct sunlight or heat sources
109
+
110
+ ### Efficiency Tips
111
+ - **Clean Surfaces**: Keep charging pad and device clean
112
+ - **Stable Placement**: Avoid vibrating surfaces
113
+ - **No Metal Objects**: Remove coins, keys, magnetic mounts
114
+ - **Update Software**: Ensure device has latest wireless charging firmware
115
+
116
+ ## Technical Specifications
117
+
118
+ ### Electrical Ratings
119
+ - **Input Voltage**: 5V/3A, 9V/2A
120
+ - **Output Power**: 15W max, 10W, 7.5W, 5W
121
+ - **Charging Efficiency**: >75% at 15W
122
+ - **Standby Power**: <0.5W when no device present
123
+ - **Frequency**: 110-148 kHz (Qi standard)
124
+
125
+ ### Environmental Conditions
126
+ - **Operating Temperature**: 32°F to 104°F (0°C to 40°C)
127
+ - **Storage Temperature**: -4°F to 140°F (-20°C to 60°C)
128
+ - **Humidity**: 10% to 90% RH (non-condensing)
129
+ - **Altitude**: Up to 6,600 feet (2,000m)
130
+
131
+ ### Physical Specifications
132
+ - **Diameter**: 4.3 inches (110mm)
133
+ - **Thickness**: 0.4 inches (10mm)
134
+ - **Weight**: 4.2 oz (120g)
135
+ - **Top Material**: Premium aluminum
136
+ - **Base Material**: ABS plastic with rubber grips
137
+
138
+ ## Troubleshooting
139
+
140
+ ### Common Issues
141
+
142
+ **Device Not Charging**
143
+ - Check device Qi compatibility
144
+ - Remove thick or metal cases
145
+ - Center device on charging pad
146
+ - Verify power adapter connection
147
+
148
+ **Slow Charging Speed**
149
+ - Use included QC 3.0 adapter
150
+ - Remove case if thick (>5mm)
151
+ - Ensure proper device alignment
152
+ - Check for overheating
153
+
154
+ **LED Shows Red**
155
+ - Remove metal objects from pad
156
+ - Clean charging surfaces
157
+ - Reposition device
158
+ - Check for foreign objects
159
+
160
+ **Intermittent Charging**
161
+ - Ensure stable placement
162
+ - Check for loose connections
163
+ - Clean charging contacts
164
+ - Verify case compatibility
165
+
166
+ ### Advanced Troubleshooting
167
+ - **Firmware Updates**: Some phones may need software updates for optimal charging
168
+ - **Adapter Compatibility**: Use QC 3.0 or PD adapters for fast charging
169
+ - **Environmental Factors**: Avoid extreme temperatures and magnetic fields
170
+
171
+ ## Care & Maintenance
172
+
173
+ ### Cleaning Instructions
174
+ - **Power Off**: Disconnect from power before cleaning
175
+ - **Dry Cloth**: Use lint-free cloth for surface cleaning
176
+ - **No Liquids**: Do not use water or cleaning solutions
177
+ - **Gentle Cleaning**: Avoid abrasive materials that could scratch aluminum
178
+
179
+ ### Storage
180
+ - **Cool, Dry Place**: Store in temperature-controlled environment
181
+ - **Avoid Pressure**: Don't place heavy objects on charging pad
182
+ - **Cable Management**: Coil cable loosely to prevent damage
183
+
184
+ ## What's Included
185
+
186
+ ### Package Contents
187
+ - 1x TMC Wireless Charging Pad
188
+ - 1x USB-C to USB-A Cable (3ft)
189
+ - 1x QC 3.0 Wall Adapter (18W)
190
+ - 1x Quick Start Guide
191
+ - 1x Warranty Registration Card
192
+
193
+ ## Warranty & Support
194
+
195
+ ### Warranty Coverage
196
+ - **Duration**: 2-year limited warranty
197
+ - **Coverage**: Manufacturing defects and material failures
198
+ - **Exclusions**: Physical damage, misuse, normal wear
199
+
200
+ ### Customer Support
201
+ - **Website**: support.toomanycables.com/wireless
202
+ - **Email**: support@toomanycables.com
203
+ - **Phone**: 1-800-TMC-HELP
204
+ - **Live Chat**: Available 24/7 on website
205
+
206
+ ### Warranty Registration
207
+ Register within 30 days for:
208
+ - Full warranty coverage
209
+ - Product notifications
210
+ - Technical support priority
211
+
212
+ ---
213
+
214
+ **Model**: TMC-WIRELESS-15W-QI
215
+ **Manual Version**: 1.4
216
+ **Last Updated**: October 2025
217
+ **Document**: TMC-WIRELESS-MANUAL-V1.4
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ Flask==2.3.3
2
+ Flask-CORS==4.0.0
3
+ requests==2.31.0
4
+ Werkzeug==2.3.7
5
+ Flask-Limiter==3.1.0
6
+ Flask-WTF==1.1.1
7
+ chromadb==0.4.22
8
+ sentence-transformers==2.7.0
9
+ numpy==1.24.3
10
+ openai>=1.0.0
scripts/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ """
2
+ Helper scripts for TMC Chatbot
3
+ """
scripts/database.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sqlite3
2
+ import os
3
+ import secrets
4
+ import hashlib
5
+ from typing import Optional, Dict, List
6
+
7
+ class DatabaseManager:
8
+ def __init__(self, db_path=None):
9
+ self.db_path = db_path or os.environ.get('DATABASE_PATH', 'tmc_customer_service.db')
10
+ os.makedirs(os.path.dirname(self.db_path) or '.', exist_ok=True)
11
+ self.init_database()
12
+
13
+ def get_connection(self):
14
+ conn = sqlite3.connect(self.db_path)
15
+ conn.row_factory = sqlite3.Row
16
+ return conn
17
+
18
+ def init_database(self):
19
+ with self.get_connection() as conn:
20
+ c = conn.cursor()
21
+ c.execute('''CREATE TABLE IF NOT EXISTS users (
22
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
23
+ email TEXT UNIQUE NOT NULL,
24
+ first_name TEXT NOT NULL,
25
+ last_name TEXT NOT NULL,
26
+ password_hash TEXT NOT NULL,
27
+ salt TEXT NOT NULL,
28
+ phone TEXT,
29
+ company TEXT,
30
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
31
+ is_active BOOLEAN DEFAULT 1,
32
+ role TEXT DEFAULT 'user'
33
+ )''')
34
+ c.execute('''CREATE TABLE IF NOT EXISTS sessions (
35
+ id TEXT PRIMARY KEY,
36
+ user_id INTEGER,
37
+ ip_address TEXT,
38
+ user_agent TEXT,
39
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
40
+ expires_at TIMESTAMP NOT NULL,
41
+ is_active BOOLEAN DEFAULT 1,
42
+ FOREIGN KEY(user_id) REFERENCES users(id)
43
+ )''')
44
+ c.execute('''CREATE TABLE IF NOT EXISTS conversations (
45
+ id TEXT PRIMARY KEY,
46
+ user_id INTEGER,
47
+ session_id TEXT,
48
+ title TEXT,
49
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
50
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
51
+ is_active BOOLEAN DEFAULT 1,
52
+ FOREIGN KEY(user_id) REFERENCES users(id)
53
+ )''')
54
+ c.execute('''CREATE TABLE IF NOT EXISTS messages (
55
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
56
+ conversation_id TEXT NOT NULL,
57
+ role TEXT NOT NULL,
58
+ content TEXT NOT NULL,
59
+ timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
60
+ model_used TEXT,
61
+ response_time_ms INTEGER,
62
+ FOREIGN KEY(conversation_id) REFERENCES conversations(id)
63
+ )''')
64
+ c.execute('''CREATE TABLE IF NOT EXISTS support_tickets (
65
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
66
+ ticket_number TEXT UNIQUE NOT NULL,
67
+ user_id INTEGER NOT NULL,
68
+ conversation_id TEXT,
69
+ subject TEXT NOT NULL,
70
+ description TEXT NOT NULL,
71
+ category TEXT NOT NULL,
72
+ priority TEXT DEFAULT 'medium',
73
+ status TEXT DEFAULT 'open',
74
+ assigned_agent TEXT,
75
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
76
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
77
+ resolved_at TIMESTAMP,
78
+ FOREIGN KEY(user_id) REFERENCES users(id)
79
+ )''')
80
+ c.execute('''CREATE TABLE IF NOT EXISTS ticket_updates (
81
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
82
+ ticket_id INTEGER NOT NULL,
83
+ user_id INTEGER,
84
+ update_type TEXT DEFAULT 'note',
85
+ message TEXT NOT NULL,
86
+ is_internal BOOLEAN DEFAULT 0,
87
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
88
+ FOREIGN KEY(ticket_id) REFERENCES support_tickets(id)
89
+ )''')
90
+ c.execute('''CREATE TABLE IF NOT EXISTS ticket_categories (
91
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
92
+ name TEXT UNIQUE NOT NULL,
93
+ description TEXT,
94
+ default_priority TEXT DEFAULT 'medium',
95
+ is_active BOOLEAN DEFAULT 1
96
+ )''')
97
+ conn.commit()
98
+ c.execute("INSERT OR IGNORE INTO ticket_categories (name, description) VALUES ('General', 'General inquiries')")
99
+ conn.commit()
100
+
101
+ def hash_password(self, password: str):
102
+ salt = secrets.token_hex(32)
103
+ ph = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000).hex()
104
+ return ph, salt
105
+
106
+ def verify_password(self, password, phash, salt):
107
+ return hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000).hex() == phash
108
+
109
+ def create_user(self, email, first_name, last_name, password, phone=None, company=None) -> Optional[int]:
110
+ try:
111
+ phash, salt = self.hash_password(password)
112
+ with self.get_connection() as conn:
113
+ cur = conn.cursor()
114
+ cur.execute('''INSERT INTO users (email, first_name, last_name, password_hash, salt, phone, company)
115
+ VALUES (?,?,?,?,?,?,?)''',
116
+ (email, first_name, last_name, phash, salt, phone, company))
117
+ uid = cur.lastrowid
118
+ conn.commit()
119
+ return uid
120
+ except sqlite3.IntegrityError:
121
+ return None
122
+
123
+ def authenticate_user(self, email, password) -> Optional[Dict]:
124
+ with self.get_connection() as conn:
125
+ cur = conn.cursor()
126
+ cur.execute('SELECT id, email, first_name, last_name, password_hash, salt, is_active FROM users WHERE email = ?', (email,))
127
+ row = cur.fetchone()
128
+ if row and row['is_active'] and self.verify_password(password, row['password_hash'], row['salt']):
129
+ return dict(row)
130
+ return None
131
+
132
+ def create_session(self, user_id, ip, ua, hours=24) -> str:
133
+ sid = secrets.token_urlsafe(32)
134
+ with self.get_connection() as conn:
135
+ conn.execute('INSERT INTO sessions (id, user_id, ip_address, user_agent, expires_at) VALUES (?,?,?,?, datetime("now", "+? hours"))',
136
+ (sid, user_id, ip, ua[:255], hours))
137
+ conn.commit()
138
+ return sid
139
+
140
+ def get_user_by_session(self, session_id) -> Optional[Dict]:
141
+ with self.get_connection() as conn:
142
+ cur = conn.cursor()
143
+ cur.execute('''SELECT u.id, u.email, u.first_name, u.last_name, u.role
144
+ FROM users u JOIN sessions s ON u.id = s.user_id
145
+ WHERE s.id = ? AND s.is_active = 1 AND s.expires_at > CURRENT_TIMESTAMP''', (session_id,))
146
+ row = cur.fetchone()
147
+ return dict(row) if row else None
148
+
149
+ def get_user_role(self, user_id) -> str:
150
+ with self.get_connection() as conn:
151
+ cur = conn.cursor()
152
+ cur.execute('SELECT role FROM users WHERE id = ?', (user_id,))
153
+ row = cur.fetchone()
154
+ return row['role'] if row else 'user'
155
+
156
+ def create_conversation(self, user_id=None, session_id=None, title=None) -> str:
157
+ cid = secrets.token_urlsafe(16)
158
+ with self.get_connection() as conn:
159
+ conn.execute('INSERT INTO conversations (id, user_id, session_id, title) VALUES (?,?,?,?)',
160
+ (cid, user_id, session_id, title))
161
+ conn.commit()
162
+ return cid
163
+
164
+ def add_message(self, conversation_id, role, content, model_used=None, response_time_ms=None):
165
+ with self.get_connection() as conn:
166
+ cur = conn.cursor()
167
+ cur.execute('''INSERT INTO messages (conversation_id, role, content, model_used, response_time_ms)
168
+ VALUES (?,?,?,?,?)''', (conversation_id, role, content, model_used, response_time_ms))
169
+ conn.execute('UPDATE conversations SET updated_at = CURRENT_TIMESTAMP WHERE id = ?', (conversation_id,))
170
+ conn.commit()
171
+ return cur.lastrowid
172
+
173
+ def get_conversation_history(self, conversation_id, limit=50) -> List[Dict]:
174
+ with self.get_connection() as conn:
175
+ cur = conn.cursor()
176
+ cur.execute('SELECT is_active FROM conversations WHERE id = ?', (conversation_id,))
177
+ if not cur.fetchone():
178
+ return []
179
+ cur.execute('''SELECT role, content, timestamp, model_used FROM messages
180
+ WHERE conversation_id = ? ORDER BY timestamp LIMIT ?''', (conversation_id, limit))
181
+ return [dict(row) for row in cur.fetchall()]
182
+
183
+ def create_support_ticket(self, user_id, subject, description, category, conversation_id=None, priority='medium') -> str:
184
+ import random, string
185
+ tn = 'TMC-' + ''.join(random.choices(string.digits, k=6))
186
+ with self.get_connection() as conn:
187
+ cur = conn.cursor()
188
+ cur.execute('''INSERT INTO support_tickets (ticket_number, user_id, conversation_id, subject, description, category, priority)
189
+ VALUES (?,?,?,?,?,?,?)''', (tn, user_id, conversation_id, subject, description, category, priority))
190
+ conn.commit()
191
+ return tn
192
+
193
+ def get_ticket_by_number(self, ticket_number) -> Optional[Dict]:
194
+ with self.get_connection() as conn:
195
+ cur = conn.cursor()
196
+ cur.execute('SELECT * FROM support_tickets WHERE ticket_number = ?', (ticket_number,))
197
+ row = cur.fetchone()
198
+ return dict(row) if row else None
199
+
200
+ def get_ticket_updates(self, ticket_id, include_internal=False) -> List[Dict]:
201
+ with self.get_connection() as conn:
202
+ cur = conn.cursor()
203
+ if include_internal:
204
+ cur.execute('SELECT * FROM ticket_updates WHERE ticket_id = ? ORDER BY created_at', (ticket_id,))
205
+ else:
206
+ cur.execute('SELECT * FROM ticket_updates WHERE ticket_id = ? AND is_internal = 0 ORDER BY created_at', (ticket_id,))
207
+ return [dict(row) for row in cur.fetchall()]
208
+
209
+ def add_ticket_update(self, ticket_id, user_id, message, update_type='note', is_internal=False) -> int:
210
+ with self.get_connection() as conn:
211
+ cur = conn.cursor()
212
+ cur.execute('''INSERT INTO ticket_updates (ticket_id, user_id, update_type, message, is_internal)
213
+ VALUES (?,?,?,?,?)''', (ticket_id, user_id, update_type, message, is_internal))
214
+ conn.execute('UPDATE support_tickets SET updated_at = CURRENT_TIMESTAMP WHERE id = ?', (ticket_id,))
215
+ conn.commit()
216
+ return cur.lastrowid
217
+
218
+ def get_user_tickets(self, user_id, limit=20) -> List[Dict]:
219
+ with self.get_connection() as conn:
220
+ cur = conn.cursor()
221
+ cur.execute('SELECT * FROM support_tickets WHERE user_id = ? ORDER BY created_at DESC LIMIT ?', (user_id, limit))
222
+ return [dict(row) for row in cur.fetchall()]
223
+
224
+ def get_tickets_by_status(self, status, limit=50) -> List[Dict]:
225
+ with self.get_connection() as conn:
226
+ cur = conn.cursor()
227
+ if status:
228
+ cur.execute('SELECT * FROM support_tickets WHERE status = ? ORDER BY created_at DESC LIMIT ?', (status, limit))
229
+ else:
230
+ cur.execute('SELECT * FROM support_tickets ORDER BY created_at DESC LIMIT ?', (limit,))
231
+ return [dict(row) for row in cur.fetchall()]
232
+
233
+ # Stubs for additional methods used in original app
234
+ def categorize_ticket_content(self, text):
235
+ return "General"
236
+
237
+ def escalate_ticket(self, ticket_id, reason, user_id=None):
238
+ with self.get_connection() as conn:
239
+ conn.execute("UPDATE support_tickets SET priority = 'high' WHERE id = ?", (ticket_id,))
240
+ conn.commit()
241
+ return True
242
+
243
+ def check_escalation_needed(self, ticket_id):
244
+ return {"needs_escalation": False}
scripts/init_database.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from .database import DatabaseManager
3
+
4
+ def init_sample_data():
5
+ db = DatabaseManager()
6
+ admin = db.create_user('admin@toomanycables.com', 'Admin', 'User', 'CHANGE_ME_ADMIN_PASSWORD', company='Too Many Cables')
7
+ if admin:
8
+ with db.get_connection() as conn:
9
+ conn.execute("UPDATE users SET role = 'admin' WHERE id = ?", (admin,))
10
+ conn.commit()
11
+ print("Admin created with password 'CHANGE_ME_ADMIN_PASSWORD'. Change it immediately via UI or DB.")
12
+ db.create_user('customer@example.com', 'John', 'Customer', 'customer123', company='Example Corp')
13
+ print("Sample data initialized.")
14
+
15
+ if __name__ == '__main__':
16
+ init_sample_data()
scripts/knowledge_base_manager.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pathlib import Path
3
+ from typing import Dict, List, Optional
4
+
5
+ class KnowledgeBaseManager:
6
+ def __init__(self, knowledge_base_path: str = "knowledge_base"):
7
+ self.kb_path = Path(knowledge_base_path)
8
+ self.documents = {}
9
+ self.kb_path.mkdir(exist_ok=True)
10
+
11
+ def scan_documents(self) -> Dict:
12
+ documents = {}
13
+ categories = {
14
+ 'faqs': 'Frequently Asked Questions',
15
+ 'policies': 'Company Policies',
16
+ 'product_manuals': 'Product Manuals',
17
+ # 'development' intentionally omitted
18
+ }
19
+ for category, desc in categories.items():
20
+ cat_path = self.kb_path / category
21
+ if cat_path.exists():
22
+ docs = []
23
+ for f in cat_path.glob('*.md'):
24
+ docs.append(self._analyze_document(f, category))
25
+ documents[category] = {'description': desc, 'documents': docs}
26
+ self.documents = documents
27
+ return documents
28
+
29
+ def _analyze_document(self, file_path: Path, category: str) -> Dict:
30
+ with open(file_path, 'r', encoding='utf-8') as f:
31
+ content = f.read()
32
+ title = next((line.strip('# ').strip() for line in content.split('\n') if line.startswith('# ')), file_path.stem)
33
+ return {
34
+ 'filename': file_path.name,
35
+ 'title': title,
36
+ 'category': category,
37
+ 'path': str(file_path.relative_to(self.kb_path)),
38
+ 'size': file_path.stat().st_size,
39
+ 'word_count': len(content.split()),
40
+ 'char_count': len(content)
41
+ }
42
+
43
+ def load_document_content(self, document_path: str) -> Optional[str]:
44
+ full = self.kb_path / document_path
45
+ if full.exists():
46
+ with open(full, 'r', encoding='utf-8') as f:
47
+ return f.read()
48
+ return None
49
+
50
+ def search_documents(self, query: str, category: Optional[str] = None) -> List[Dict]:
51
+ results = []
52
+ ql = query.lower()
53
+ for cat, info in self.documents.items():
54
+ if category and cat != category:
55
+ continue
56
+ for doc in info['documents']:
57
+ content = self.load_document_content(doc['path'])
58
+ if not content:
59
+ continue
60
+ if ql in content.lower() or ql in doc['title'].lower():
61
+ score = content.lower().count(ql)
62
+ results.append({**doc, 'relevance_score': score})
63
+ results.sort(key=lambda x: x['relevance_score'], reverse=True)
64
+ return results
scripts/rag_helper.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from typing import List, Dict
3
+ from .knowledge_base_manager import KnowledgeBaseManager
4
+
5
+ try:
6
+ from .vector_rag_manager import VectorRAGManager
7
+ VECTOR_AVAILABLE = True
8
+ except ImportError:
9
+ VECTOR_AVAILABLE = False
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class RAGHelper:
14
+ def __init__(self, knowledge_base_path: str = "knowledge_base", use_vector_search: bool = True):
15
+ self.kb_manager = KnowledgeBaseManager(knowledge_base_path)
16
+ self.kb_manager.scan_documents()
17
+ self.use_vector_search = use_vector_search and VECTOR_AVAILABLE
18
+ self.vector_rag = None
19
+ if self.use_vector_search:
20
+ try:
21
+ self.vector_rag = VectorRAGManager(knowledge_base_path, vector_db_path="/app/data/vector_db")
22
+ logger.info("Vector RAG initialized")
23
+ except Exception as e:
24
+ logger.warning(f"Vector RAG failed: {e}")
25
+ self.use_vector_search = False
26
+ self.max_context_docs = 3
27
+ self.similarity_threshold = 0.30
28
+
29
+ def _route_query_to_categories(self, query: str) -> List[str]:
30
+ ql = query.lower()
31
+ cat_keywords = {
32
+ 'policies': ['return','refund','warranty','policy','shipping'],
33
+ 'faqs': ['how','what','why','help','troubleshoot','problem'],
34
+ 'product_manuals': ['spec','manual','guide','connect','cable','hdmi','usb']
35
+ }
36
+ scores = {}
37
+ for cat, kw in cat_keywords.items():
38
+ score = sum(1 for k in kw if k in ql)
39
+ if score:
40
+ scores[cat] = score
41
+ if scores:
42
+ return sorted(scores, key=scores.get, reverse=True)
43
+ return ['policies','faqs','product_manuals']
44
+
45
+ def get_relevant_context(self, query: str) -> str:
46
+ categories = self._route_query_to_categories(query)
47
+ if self.use_vector_search and self.vector_rag:
48
+ try:
49
+ results = self.vector_rag.retrieve_and_rerank_filtered(
50
+ query, target_categories=categories, initial_k=20, final_k=3,
51
+ similarity_threshold=self.similarity_threshold
52
+ )
53
+ return self._build_context_from_results(results)
54
+ except Exception as e:
55
+ logger.warning(f"Vector search failed: {e}, falling back to keyword")
56
+ return self._get_keyword_context(query)
57
+
58
+ def _get_keyword_context(self, query: str) -> str:
59
+ results = self.kb_manager.search_documents(query)
60
+ context = ""
61
+ for r in results[:self.max_context_docs]:
62
+ content = self.kb_manager.load_document_content(r['path'])
63
+ if content:
64
+ context += f"\n--- {r['title']} (Category: {r['category']}) ---\n{content[:1500]}\n"
65
+ return context
66
+
67
+ def _build_context_from_results(self, results: List[Dict]) -> str:
68
+ if not results:
69
+ return ""
70
+ chunks = []
71
+ for res in results:
72
+ doc = res['document']
73
+ meta = res['metadata']
74
+ chunks.append(f"--- {meta['document_title']} (Category: {meta['category']}) ---\n{doc[:1200]}")
75
+ return "\n".join(chunks[:3])
76
+
77
+ def get_knowledge_base_stats(self) -> Dict:
78
+ stats = self.kb_manager.get_stats() if hasattr(self.kb_manager, 'get_stats') else {'total_documents': 0}
79
+ stats['vector_search_available'] = self.use_vector_search
80
+ return stats
81
+
82
+ def ensure_vector_index(self, force_reindex: bool = False):
83
+ if self.vector_rag:
84
+ return self.vector_rag.index_documents(force_reindex=force_reindex)
85
+ return {"error": "Vector not available"}
scripts/vector_rag_manager.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ from pathlib import Path
4
+ from typing import List, Dict
5
+ import chromadb
6
+ from chromadb.config import Settings
7
+ from sentence_transformers import SentenceTransformer
8
+ from .knowledge_base_manager import KnowledgeBaseManager
9
+
10
+ os.environ['ANONYMIZED_TELEMETRY'] = 'False'
11
+ os.environ['CHROMA_TELEMETRY_ENABLED'] = 'false'
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class VectorRAGManager:
16
+ def __init__(self, knowledge_base_path: str, vector_db_path: str = "vector_db", embedding_model: str = "all-MiniLM-L6-v2"):
17
+ self.kb_path = Path(knowledge_base_path)
18
+ self.vector_db_path = Path(vector_db_path)
19
+ self.vector_db_path.mkdir(exist_ok=True, parents=True)
20
+ self.kb_manager = KnowledgeBaseManager(knowledge_base_path)
21
+ self.chroma_client = chromadb.PersistentClient(path=str(self.vector_db_path), settings=Settings(anonymized_telemetry=False))
22
+ self.embedding_model = SentenceTransformer(embedding_model)
23
+ self.collection_name = "tmc_documents"
24
+ self._init_collection()
25
+ self.chunk_size = 800
26
+ self.chunk_overlap = 120
27
+
28
+ def _init_collection(self):
29
+ try:
30
+ self.collection = self.chroma_client.get_collection(self.collection_name)
31
+ except:
32
+ self.collection = self.chroma_client.create_collection(self.collection_name)
33
+
34
+ def chunk_text(self, text: str) -> List[str]:
35
+ if len(text) <= self.chunk_size:
36
+ return [text]
37
+ chunks = []
38
+ start = 0
39
+ while start < len(text):
40
+ end = min(start + self.chunk_size, len(text))
41
+ if end < len(text):
42
+ for i in range(end, max(start, end-200), -1):
43
+ if text[i] in '.!?\n':
44
+ end = i+1
45
+ break
46
+ chunks.append(text[start:end].strip())
47
+ start = end - self.chunk_overlap
48
+ return [c for c in chunks if len(c) > 50]
49
+
50
+ def generate_embedding(self, text: str) -> List[float]:
51
+ return self.embedding_model.encode(text).tolist()
52
+
53
+ def index_documents(self, force_reindex: bool = False) -> Dict:
54
+ if force_reindex and self.collection.count() > 0:
55
+ self.chroma_client.delete_collection(self.collection_name)
56
+ self._init_collection()
57
+ self.kb_manager.scan_documents()
58
+ stats = {"documents": 0, "chunks": 0}
59
+ for category, cat_info in self.kb_manager.documents.items():
60
+ if category == 'development':
61
+ logger.info(f"Skipping development folder")
62
+ continue
63
+ for doc in cat_info['documents']:
64
+ content = self.kb_manager.load_document_content(doc['path'])
65
+ if not content:
66
+ continue
67
+ chunks = self.chunk_text(content)
68
+ if not chunks:
69
+ continue
70
+ ids = []
71
+ embeds = []
72
+ texts = []
73
+ metas = []
74
+ for i, chunk in enumerate(chunks):
75
+ cid = f"{doc['filename']}_{i}"
76
+ ids.append(cid)
77
+ texts.append(chunk)
78
+ embeds.append(self.generate_embedding(chunk))
79
+ metas.append({
80
+ "document_title": doc['title'],
81
+ "document_path": doc['path'],
82
+ "category": category,
83
+ "chunk_index": i
84
+ })
85
+ self.collection.add(ids=ids, embeddings=embeds, documents=texts, metadatas=metas)
86
+ stats["documents"] += 1
87
+ stats["chunks"] += len(chunks)
88
+ logger.info(f"Indexed {stats['documents']} docs, {stats['chunks']} chunks")
89
+ return stats
90
+
91
+ def semantic_search(self, query: str, n_results: int = 5) -> List[Dict]:
92
+ if self.collection.count() == 0:
93
+ return []
94
+ q_emb = self.generate_embedding(query)
95
+ results = self.collection.query(query_embeddings=[q_emb], n_results=n_results, include=["documents","metadatas","distances"])
96
+ formatted = []
97
+ if results['documents'] and results['documents'][0]:
98
+ for doc, meta, dist in zip(results['documents'][0], results['metadatas'][0], results['distances'][0]):
99
+ similarity = max(0.0, 1.0 - (dist / 2.0))
100
+ formatted.append({"document": doc, "metadata": meta, "similarity": similarity})
101
+ return formatted
102
+
103
+ def retrieve_and_rerank_filtered(self, query: str, target_categories: List[str], initial_k: int = 20, final_k: int = 3, similarity_threshold: float = 0.30) -> List[Dict]:
104
+ candidates = self.semantic_search(query, n_results=initial_k)
105
+ filtered = [c for c in candidates if c['similarity'] >= similarity_threshold and c['metadata'].get('category') in target_categories]
106
+ return filtered[:final_k]
107
+
108
+ def get_collection_stats(self) -> Dict:
109
+ return {"total_chunks": self.collection.count()}
static/chat.js ADDED
@@ -0,0 +1,298 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Chat functionality for Too Many Cables customer service
2
+ class ChatInterface {
3
+ constructor() {
4
+ this.chatMessages = document.getElementById('chat-messages');
5
+ this.messageInput = document.getElementById('message-input');
6
+ this.sendButton = document.getElementById('send-button');
7
+ this.chatForm = document.getElementById('chat-form');
8
+ this.clearButton = document.getElementById('clear-chat');
9
+ this.typingIndicator = document.getElementById('typing-indicator');
10
+ this.statusDot = document.getElementById('status-dot');
11
+ this.statusText = document.getElementById('status-text');
12
+ this.agentStatus = document.getElementById('agent-status');
13
+
14
+ this.conversationId = null;
15
+ this.isConnected = false;
16
+
17
+ this.init();
18
+ }
19
+
20
+ init() {
21
+ this.checkConnection();
22
+ this.setupEventListeners();
23
+ this.loadConversationHistory();
24
+ }
25
+
26
+ setupEventListeners() {
27
+ if (this.chatForm) {
28
+ this.chatForm.addEventListener('submit', (e) => {
29
+ e.preventDefault();
30
+ this.sendMessage();
31
+ });
32
+ }
33
+
34
+ if (this.clearButton) {
35
+ this.clearButton.addEventListener('click', () => {
36
+ this.clearConversation();
37
+ });
38
+ }
39
+
40
+ const endConversationButton = document.getElementById('end-conversation-button');
41
+ if (endConversationButton) {
42
+ endConversationButton.addEventListener('click', () => {
43
+ this.endConversation();
44
+ });
45
+ }
46
+
47
+ if (this.messageInput) {
48
+ this.messageInput.addEventListener('input', () => {
49
+ this.autoResizeTextarea();
50
+ this.toggleSendButton();
51
+ });
52
+
53
+ this.messageInput.addEventListener('keydown', (e) => {
54
+ if (e.key === 'Enter' && !e.shiftKey) {
55
+ e.preventDefault();
56
+ this.sendMessage();
57
+ }
58
+ });
59
+ }
60
+ }
61
+
62
+ async checkConnection() {
63
+ try {
64
+ const response = await fetch('/api/health');
65
+ if (response.ok) {
66
+ this.updateConnectionStatus(true);
67
+ } else {
68
+ this.updateConnectionStatus(false);
69
+ }
70
+ } catch (error) {
71
+ console.error('Connection check failed:', error);
72
+ this.updateConnectionStatus(false);
73
+ }
74
+ }
75
+
76
+ updateConnectionStatus(connected) {
77
+ this.isConnected = connected;
78
+ if (this.statusDot && this.statusText) {
79
+ if (connected) {
80
+ this.statusDot.className = 'status-dot connected';
81
+ this.statusText.textContent = 'Connected';
82
+ } else {
83
+ this.statusDot.className = 'status-dot disconnected';
84
+ this.statusText.textContent = 'Connection issues';
85
+ }
86
+ }
87
+ if (this.agentStatus) {
88
+ this.agentStatus.textContent = connected ? 'Online' : 'Offline';
89
+ }
90
+ }
91
+
92
+ autoResizeTextarea() {
93
+ if (this.messageInput) {
94
+ this.messageInput.style.height = 'auto';
95
+ this.messageInput.style.height = Math.min(this.messageInput.scrollHeight, 120) + 'px';
96
+ }
97
+ }
98
+
99
+ toggleSendButton() {
100
+ if (this.sendButton && this.messageInput) {
101
+ this.sendButton.disabled = this.messageInput.value.trim().length === 0;
102
+ }
103
+ }
104
+
105
+ async sendMessage() {
106
+ const message = this.messageInput.value.trim();
107
+ if (!message || !this.isConnected) return;
108
+
109
+ this.addMessage(message, 'user');
110
+ this.messageInput.value = '';
111
+ this.messageInput.style.height = 'auto';
112
+ this.toggleSendButton();
113
+ this.showTypingIndicator();
114
+
115
+ try {
116
+ const controller = new AbortController();
117
+ const timeoutId = setTimeout(() => controller.abort(), 120000);
118
+
119
+ // CRITICAL FIX: Add credentials: 'include'
120
+ const response = await fetch('/api/chat', {
121
+ method: 'POST',
122
+ headers: {
123
+ 'Content-Type': 'application/json',
124
+ },
125
+ body: JSON.stringify({
126
+ message: message,
127
+ conversation_id: this.conversationId
128
+ }),
129
+ signal: controller.signal,
130
+ cache: 'no-cache',
131
+ mode: 'cors',
132
+ credentials: 'include' // <-- THIS LINE FIXES THE NETWORK ERROR
133
+ });
134
+
135
+ clearTimeout(timeoutId);
136
+ const data = await response.json();
137
+
138
+ if (data.success) {
139
+ this.conversationId = data.conversation_id;
140
+ if (typeof updateConversationId === 'function') {
141
+ updateConversationId(this.conversationId);
142
+ }
143
+ this.addMessage(data.response, 'assistant', {
144
+ responseTime: data.response_time_ms,
145
+ model: data.model_used
146
+ });
147
+ } else {
148
+ const errorMessage = data.error || 'Sorry, I encountered an error. Please try again.';
149
+ this.addMessage(errorMessage, 'assistant', { isError: true });
150
+ }
151
+ } catch (error) {
152
+ console.error('Error sending message:', error);
153
+ this.addMessage('Connection error. Please check your internet connection and try again.', 'assistant', { isError: true });
154
+ } finally {
155
+ this.hideTypingIndicator();
156
+ }
157
+ }
158
+
159
+ addMessage(content, role, metadata = {}) {
160
+ const messageDiv = document.createElement('div');
161
+ messageDiv.className = `message ${role}-message`;
162
+ const timestamp = new Date().toLocaleTimeString();
163
+ let messageHTML = '';
164
+ if (role === 'user') {
165
+ messageHTML = `
166
+ <div class="message-content">
167
+ <div class="message-text">${this.escapeHtml(content)}</div>
168
+ <div class="message-time">${timestamp}</div>
169
+ </div>
170
+ <div class="message-avatar">👤</div>
171
+ `;
172
+ } else {
173
+ const errorClass = metadata.isError ? ' error' : '';
174
+ const responseTimeText = metadata.responseTime ? ` (${metadata.responseTime}ms)` : '';
175
+ messageHTML = `
176
+ <div class="message-avatar">🤖</div>
177
+ <div class="message-content${errorClass}">
178
+ <div class="message-text">${this.escapeHtml(content)}</div>
179
+ <div class="message-time">${timestamp}${responseTimeText}</div>
180
+ </div>
181
+ `;
182
+ }
183
+ messageDiv.innerHTML = messageHTML;
184
+ if (this.chatMessages) {
185
+ this.chatMessages.appendChild(messageDiv);
186
+ this.scrollToBottom();
187
+ }
188
+ }
189
+
190
+ showTypingIndicator() {
191
+ if (this.typingIndicator) {
192
+ this.typingIndicator.style.display = 'flex';
193
+ this.scrollToBottom();
194
+ }
195
+ }
196
+
197
+ hideTypingIndicator() {
198
+ if (this.typingIndicator) {
199
+ this.typingIndicator.style.display = 'none';
200
+ }
201
+ }
202
+
203
+ scrollToBottom() {
204
+ if (this.chatMessages) {
205
+ this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
206
+ }
207
+ }
208
+
209
+ async clearConversation() {
210
+ if (!this.conversationId) {
211
+ this.clearChatUI();
212
+ return;
213
+ }
214
+ if (confirm('Are you sure you want to clear this conversation?')) {
215
+ try {
216
+ const response = await fetch(`/api/conversation/${this.conversationId}/clear`, {
217
+ method: 'POST'
218
+ });
219
+ if (response.ok) {
220
+ this.clearChatUI();
221
+ this.conversationId = null;
222
+ } else {
223
+ alert('Failed to clear conversation. Please try again.');
224
+ }
225
+ } catch (error) {
226
+ console.error('Error clearing conversation:', error);
227
+ alert('Error clearing conversation. Please try again.');
228
+ }
229
+ }
230
+ }
231
+
232
+ async endConversation() {
233
+ if (!this.conversationId) {
234
+ alert('No active conversation to end.');
235
+ return;
236
+ }
237
+ if (confirm('End this conversation and save a summary to any mentioned tickets?')) {
238
+ try {
239
+ const response = await fetch('/api/conversation/end', {
240
+ method: 'POST',
241
+ headers: { 'Content-Type': 'application/json' },
242
+ body: JSON.stringify({ conversation_id: this.conversationId })
243
+ });
244
+ if (response.ok) {
245
+ const result = await response.json();
246
+ if (result.success) {
247
+ alert(result.message || 'Conversation ended successfully!');
248
+ this.clearChatUI();
249
+ this.conversationId = null;
250
+ } else {
251
+ alert(result.message || 'Failed to end conversation properly.');
252
+ }
253
+ } else {
254
+ alert('Failed to end conversation. Please try again.');
255
+ }
256
+ } catch (error) {
257
+ console.error('Error ending conversation:', error);
258
+ alert('Error ending conversation. Please try again.');
259
+ }
260
+ }
261
+ }
262
+
263
+ clearChatUI() {
264
+ if (this.chatMessages) {
265
+ const welcomeMessage = this.chatMessages.querySelector('.welcome-message');
266
+ this.chatMessages.innerHTML = '';
267
+ if (welcomeMessage) {
268
+ this.chatMessages.appendChild(welcomeMessage);
269
+ }
270
+ }
271
+ }
272
+
273
+ async loadConversationHistory() {
274
+ try {
275
+ const response = await fetch('/api/user');
276
+ if (response.ok) {
277
+ const userData = await response.json();
278
+ if (userData.success) {
279
+ console.log('User authenticated:', userData.user.name);
280
+ }
281
+ }
282
+ } catch (error) {
283
+ console.log('User not authenticated');
284
+ }
285
+ }
286
+
287
+ escapeHtml(text) {
288
+ const div = document.createElement('div');
289
+ div.textContent = text;
290
+ return div.innerHTML;
291
+ }
292
+ }
293
+
294
+ document.addEventListener('DOMContentLoaded', function() {
295
+ if (document.getElementById('chat-messages')) {
296
+ new ChatInterface();
297
+ }
298
+ });
static/script.js ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Too Many Cables - Main Website JavaScript
2
+ class TMCWebsite {
3
+ constructor() {
4
+ this.currentUser = null;
5
+ this.init();
6
+ }
7
+
8
+ init() {
9
+ this.setupNavigation();
10
+ this.setupUserAuthentication();
11
+ this.checkUserStatus();
12
+ }
13
+
14
+ setupNavigation() {
15
+ const navToggle = document.getElementById('nav-toggle');
16
+ const navMenu = document.getElementById('nav-menu');
17
+
18
+ if (navToggle && navMenu) {
19
+ navToggle.addEventListener('click', () => {
20
+ navMenu.classList.toggle('active');
21
+ navToggle.classList.toggle('active');
22
+ });
23
+ }
24
+ }
25
+
26
+ setupUserAuthentication() {
27
+ // Login/logout functionality is now handled in base.html
28
+ // This method is kept for future authentication-related features
29
+ }
30
+
31
+ showModal(type) {
32
+ const modalId = type === 'login' ? 'login-modal' : 'register-modal';
33
+ const modal = document.getElementById(modalId);
34
+ if (modal) {
35
+ modal.style.display = 'flex';
36
+ }
37
+ }
38
+
39
+ hideModal(modalId) {
40
+ const modal = document.getElementById(modalId);
41
+ if (modal) {
42
+ modal.style.display = 'none';
43
+ const form = modal.querySelector('form');
44
+ if (form) form.reset();
45
+ }
46
+ }
47
+
48
+ async logout() {
49
+ // Logout functionality is now handled in base.html
50
+ // This method is kept for compatibility
51
+ }
52
+
53
+ async checkUserStatus() {
54
+ try {
55
+ const response = await fetch('/api/user');
56
+ const data = await response.json();
57
+
58
+ if (data.success) {
59
+ this.currentUser = data.user;
60
+ this.updateUserUI();
61
+ }
62
+ } catch (error) {
63
+ console.log('User not authenticated');
64
+ }
65
+ }
66
+
67
+ updateUserUI() {
68
+ const authBtn = document.getElementById('auth-btn');
69
+ const userGreeting = document.getElementById('user-greeting');
70
+ const userName = document.getElementById('user-name');
71
+ const ticketsLink = document.getElementById('tickets-link');
72
+
73
+ if (this.currentUser) {
74
+ if (authBtn) {
75
+ authBtn.textContent = 'Logout';
76
+ authBtn.title = 'Click to logout';
77
+ }
78
+ if (userGreeting) userGreeting.style.display = 'inline';
79
+ if (userName) userName.textContent = this.currentUser.name;
80
+ if (ticketsLink) ticketsLink.style.display = 'inline-block';
81
+ } else {
82
+ if (authBtn) {
83
+ authBtn.textContent = 'Login';
84
+ authBtn.title = 'Click to login';
85
+ }
86
+ if (userGreeting) userGreeting.style.display = 'none';
87
+ if (ticketsLink) ticketsLink.style.display = 'none';
88
+ }
89
+ }
90
+ }
91
+
92
+ // Initialize website functionality when DOM is loaded
93
+ document.addEventListener('DOMContentLoaded', function() {
94
+ new TMCWebsite();
95
+ });
static/style.css ADDED
@@ -0,0 +1,514 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Reset and base styles */
2
+ * {
3
+ margin: 0;
4
+ padding: 0;
5
+ box-sizing: border-box;
6
+ }
7
+
8
+ body {
9
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
10
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
11
+ min-height: 100vh;
12
+ line-height: 1.6;
13
+ }
14
+
15
+ .container {
16
+ max-width: 1200px;
17
+ margin: 0 auto;
18
+ padding: 20px;
19
+ min-height: 100vh;
20
+ display: flex;
21
+ flex-direction: column;
22
+ }
23
+
24
+ /* Header */
25
+ header {
26
+ background: rgba(255, 255, 255, 0.95);
27
+ backdrop-filter: blur(10px);
28
+ border-radius: 15px;
29
+ padding: 20px 30px;
30
+ margin-bottom: 20px;
31
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
32
+ display: flex;
33
+ justify-content: space-between;
34
+ align-items: center;
35
+ }
36
+
37
+ header h1 {
38
+ color: #333;
39
+ font-size: 2.2em;
40
+ font-weight: 700;
41
+ }
42
+
43
+ .status-indicator {
44
+ display: flex;
45
+ align-items: center;
46
+ gap: 10px;
47
+ font-weight: 500;
48
+ }
49
+
50
+ .status-dot {
51
+ width: 12px;
52
+ height: 12px;
53
+ border-radius: 50%;
54
+ background: #ffa500;
55
+ animation: pulse 2s infinite;
56
+ }
57
+
58
+ .status-dot.connected {
59
+ background: #4caf50;
60
+ animation: none;
61
+ }
62
+
63
+ .status-dot.error {
64
+ background: #f44336;
65
+ animation: none;
66
+ }
67
+
68
+ @keyframes pulse {
69
+ 0% { opacity: 1; }
70
+ 50% { opacity: 0.5; }
71
+ 100% { opacity: 1; }
72
+ }
73
+
74
+ /* Main content */
75
+ .main-content {
76
+ display: grid;
77
+ grid-template-columns: 300px 1fr;
78
+ gap: 20px;
79
+ flex: 1;
80
+ min-height: 0;
81
+ }
82
+
83
+ /* Agent panel */
84
+ .agent-panel {
85
+ background: rgba(255, 255, 255, 0.95);
86
+ backdrop-filter: blur(10px);
87
+ border-radius: 15px;
88
+ padding: 25px;
89
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
90
+ height: fit-content;
91
+ }
92
+
93
+ .agent-panel h3 {
94
+ color: #333;
95
+ margin-bottom: 15px;
96
+ font-size: 1.3em;
97
+ }
98
+
99
+ .agent-info {
100
+ display: flex;
101
+ flex-direction: column;
102
+ gap: 10px;
103
+ }
104
+
105
+ .agent-info p {
106
+ color: #666;
107
+ font-size: 14px;
108
+ margin: 5px 0;
109
+ }
110
+
111
+ .agent-info p strong {
112
+ color: #333;
113
+ min-width: 80px;
114
+ display: inline-block;
115
+ }
116
+
117
+ .agent-description {
118
+ margin-top: 15px;
119
+ padding: 15px;
120
+ background: #f8f9ff;
121
+ border-radius: 10px;
122
+ border-left: 4px solid #667eea;
123
+ font-style: italic;
124
+ }
125
+
126
+ #agent-status {
127
+ font-weight: 500;
128
+ }
129
+
130
+ #agent-status.ready {
131
+ color: #28a745;
132
+ }
133
+
134
+ #agent-status.error {
135
+ color: #dc3545;
136
+ }
137
+
138
+ #agent-status.connecting {
139
+ color: #ffc107;
140
+ }
141
+
142
+ /* Chat container */
143
+ .chat-container {
144
+ background: rgba(255, 255, 255, 0.95);
145
+ backdrop-filter: blur(10px);
146
+ border-radius: 15px;
147
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
148
+ display: flex;
149
+ flex-direction: column;
150
+ overflow: hidden;
151
+ }
152
+
153
+ .chat-header {
154
+ padding: 20px 25px;
155
+ border-bottom: 1px solid #e0e0e0;
156
+ display: flex;
157
+ justify-content: space-between;
158
+ align-items: center;
159
+ background: rgba(255, 255, 255, 0.8);
160
+ }
161
+
162
+ .chat-header h3 {
163
+ color: #333;
164
+ font-size: 1.3em;
165
+ }
166
+
167
+ .clear-btn {
168
+ padding: 8px 15px;
169
+ background: #f44336;
170
+ color: white;
171
+ border: none;
172
+ border-radius: 8px;
173
+ cursor: pointer;
174
+ font-size: 14px;
175
+ transition: all 0.3s ease;
176
+ }
177
+
178
+ .clear-btn:hover {
179
+ background: #d32f2f;
180
+ transform: translateY(-2px);
181
+ }
182
+
183
+ /* Chat messages */
184
+ .chat-messages {
185
+ flex: 1;
186
+ padding: 20px;
187
+ overflow-y: auto;
188
+ max-height: 500px;
189
+ min-height: 400px;
190
+ }
191
+
192
+ .welcome-message {
193
+ text-align: center;
194
+ color: #666;
195
+ margin-top: 50px;
196
+ }
197
+
198
+ .welcome-message h4 {
199
+ color: #333;
200
+ margin-bottom: 15px;
201
+ font-size: 1.4em;
202
+ }
203
+
204
+ .welcome-message ul {
205
+ text-align: left;
206
+ max-width: 400px;
207
+ margin: 20px auto 0;
208
+ }
209
+
210
+ .welcome-message li {
211
+ margin: 8px 0;
212
+ }
213
+
214
+ .message {
215
+ margin: 15px 0;
216
+ display: flex;
217
+ align-items: flex-start;
218
+ gap: 12px;
219
+ opacity: 0;
220
+ animation: messageSlideIn 0.3s ease forwards;
221
+ }
222
+
223
+ @keyframes messageSlideIn {
224
+ from {
225
+ opacity: 0;
226
+ transform: translateY(20px);
227
+ }
228
+ to {
229
+ opacity: 1;
230
+ transform: translateY(0);
231
+ }
232
+ }
233
+
234
+ .message.user {
235
+ flex-direction: row-reverse;
236
+ }
237
+
238
+ .message-avatar {
239
+ width: 40px;
240
+ height: 40px;
241
+ border-radius: 50%;
242
+ display: flex;
243
+ align-items: center;
244
+ justify-content: center;
245
+ font-size: 18px;
246
+ flex-shrink: 0;
247
+ }
248
+
249
+ .message.user .message-avatar {
250
+ background: linear-gradient(135deg, #667eea, #764ba2);
251
+ color: white;
252
+ }
253
+
254
+ .message.bot .message-avatar {
255
+ background: linear-gradient(135deg, #4caf50, #45a049);
256
+ color: white;
257
+ }
258
+
259
+ .message-content {
260
+ max-width: 70%;
261
+ padding: 15px 20px;
262
+ border-radius: 20px;
263
+ position: relative;
264
+ }
265
+
266
+ .message.user .message-content {
267
+ background: linear-gradient(135deg, #667eea, #764ba2);
268
+ color: white;
269
+ border-bottom-right-radius: 5px;
270
+ }
271
+
272
+ .message.bot .message-content {
273
+ background: #f8f9ff;
274
+ border: 1px solid #e0e0e0;
275
+ color: #333;
276
+ border-bottom-left-radius: 5px;
277
+ }
278
+
279
+ .message-text {
280
+ margin: 0;
281
+ word-wrap: break-word;
282
+ }
283
+
284
+ .message-time {
285
+ font-size: 11px;
286
+ opacity: 0.7;
287
+ margin-top: 5px;
288
+ }
289
+
290
+ /* Chat input */
291
+ .chat-input-container {
292
+ padding: 20px;
293
+ border-top: 1px solid #e0e0e0;
294
+ background: rgba(255, 255, 255, 0.8);
295
+ }
296
+
297
+ .input-group {
298
+ display: flex;
299
+ gap: 15px;
300
+ align-items: flex-end;
301
+ flex-wrap: wrap;
302
+ }
303
+
304
+ #message-input {
305
+ flex: 1;
306
+ padding: 15px 20px;
307
+ border: 2px solid #e0e0e0;
308
+ border-radius: 25px;
309
+ font-size: 14px;
310
+ font-family: inherit;
311
+ resize: none;
312
+ transition: all 0.3s ease;
313
+ background: white;
314
+ }
315
+
316
+ #message-input:focus {
317
+ outline: none;
318
+ border-color: #667eea;
319
+ box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
320
+ }
321
+
322
+ #message-input:disabled {
323
+ background: #f5f5f5;
324
+ color: #999;
325
+ cursor: not-allowed;
326
+ }
327
+
328
+ #send-btn {
329
+ padding: 15px 25px;
330
+ background: linear-gradient(135deg, #667eea, #764ba2);
331
+ color: white;
332
+ border: none;
333
+ border-radius: 25px;
334
+ cursor: pointer;
335
+ font-size: 14px;
336
+ font-weight: 600;
337
+ transition: all 0.3s ease;
338
+ display: flex;
339
+ align-items: center;
340
+ gap: 8px;
341
+ min-width: 100px;
342
+ justify-content: center;
343
+ }
344
+
345
+ #send-btn:hover:not(:disabled) {
346
+ transform: translateY(-2px);
347
+ box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
348
+ }
349
+
350
+ #send-btn:disabled {
351
+ background: #ccc;
352
+ cursor: not-allowed;
353
+ transform: none;
354
+ box-shadow: none;
355
+ }
356
+
357
+ .action-button {
358
+ padding: 10px 15px;
359
+ border: 2px solid #667eea;
360
+ background: transparent;
361
+ color: #667eea;
362
+ border-radius: 20px;
363
+ cursor: pointer;
364
+ font-size: 12px;
365
+ font-weight: 600;
366
+ transition: all 0.3s ease;
367
+ margin-left: 10px;
368
+ }
369
+
370
+ .action-button:hover {
371
+ background: #667eea;
372
+ color: white;
373
+ transform: translateY(-1px);
374
+ }
375
+
376
+ .action-button.end-conversation {
377
+ border-color: #e74c3c;
378
+ color: #e74c3c;
379
+ background: #ffebee;
380
+ font-weight: bold;
381
+ padding: 12px 20px;
382
+ }
383
+
384
+ .action-button.end-conversation:hover {
385
+ background: #e74c3c;
386
+ color: white;
387
+ }
388
+
389
+ .send-icon {
390
+ font-size: 16px;
391
+ }
392
+
393
+ .input-info {
394
+ display: flex;
395
+ justify-content: space-between;
396
+ align-items: center;
397
+ margin-top: 10px;
398
+ font-size: 12px;
399
+ color: #666;
400
+ }
401
+
402
+ .divider {
403
+ margin: 0 10px;
404
+ }
405
+
406
+ /* Loading overlay */
407
+ .loading-overlay {
408
+ position: fixed;
409
+ top: 0;
410
+ left: 0;
411
+ right: 0;
412
+ bottom: 0;
413
+ background: rgba(0, 0, 0, 0.5);
414
+ display: flex;
415
+ align-items: center;
416
+ justify-content: center;
417
+ z-index: 1000;
418
+ }
419
+
420
+ .loading-overlay.hidden {
421
+ display: none;
422
+ }
423
+
424
+ .loading-spinner {
425
+ background: white;
426
+ padding: 30px;
427
+ border-radius: 15px;
428
+ text-align: center;
429
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
430
+ }
431
+
432
+ .spinner {
433
+ width: 40px;
434
+ height: 40px;
435
+ border: 4px solid #f3f3f3;
436
+ border-top: 4px solid #667eea;
437
+ border-radius: 50%;
438
+ animation: spin 1s linear infinite;
439
+ margin: 0 auto 15px;
440
+ }
441
+
442
+ @keyframes spin {
443
+ 0% { transform: rotate(0deg); }
444
+ 100% { transform: rotate(360deg); }
445
+ }
446
+
447
+ /* Responsive design */
448
+ @media (max-width: 768px) {
449
+ .container {
450
+ padding: 10px;
451
+ }
452
+
453
+ .main-content {
454
+ grid-template-columns: 1fr;
455
+ gap: 15px;
456
+ }
457
+
458
+ .agent-panel {
459
+ order: 2;
460
+ }
461
+
462
+ .chat-container {
463
+ order: 1;
464
+ }
465
+
466
+ header {
467
+ padding: 15px 20px;
468
+ flex-direction: column;
469
+ gap: 15px;
470
+ text-align: center;
471
+ }
472
+
473
+ header h1 {
474
+ font-size: 1.8em;
475
+ }
476
+
477
+ .chat-messages {
478
+ max-height: 300px;
479
+ min-height: 250px;
480
+ }
481
+
482
+ .message-content {
483
+ max-width: 85%;
484
+ }
485
+
486
+ .input-group {
487
+ flex-direction: column;
488
+ gap: 10px;
489
+ }
490
+
491
+ #send-btn {
492
+ align-self: flex-end;
493
+ min-width: 120px;
494
+ }
495
+ }
496
+
497
+ /* Scrollbar styling */
498
+ .chat-messages::-webkit-scrollbar {
499
+ width: 6px;
500
+ }
501
+
502
+ .chat-messages::-webkit-scrollbar-track {
503
+ background: #f1f1f1;
504
+ border-radius: 3px;
505
+ }
506
+
507
+ .chat-messages::-webkit-scrollbar-thumb {
508
+ background: #c1c1c1;
509
+ border-radius: 3px;
510
+ }
511
+
512
+ .chat-messages::-webkit-scrollbar-thumb:hover {
513
+ background: #a8a8a8;
514
+ }
templates/about.html ADDED
File without changes
templates/admin_tickets.html ADDED
@@ -0,0 +1,888 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Admin - Ticket Management - Too Many Cables{% endblock %}
4
+
5
+ {% block description %}Administrative interface for managing customer support tickets and monitoring system performance.{% endblock %}
6
+
7
+ {% block content %}
8
+ <div class="admin-container">
9
+ <div class="page-header">
10
+ <h1 class="page-title">Admin - Ticket Management</h1>
11
+ <p class="page-subtitle">Manage customer support tickets and monitor system performance</p>
12
+ </div>
13
+
14
+ <!-- Statistics Dashboard -->
15
+ <div class="stats-grid">
16
+ <div class="stat-card">
17
+ <div class="stat-icon">📊</div>
18
+ <div class="stat-content">
19
+ <h3 id="total-tickets">-</h3>
20
+ <p>Total Tickets</p>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="stat-card">
25
+ <div class="stat-icon">🟢</div>
26
+ <div class="stat-content">
27
+ <h3 id="open-tickets">-</h3>
28
+ <p>Open Tickets</p>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="stat-card">
33
+ <div class="stat-icon">🔵</div>
34
+ <div class="stat-content">
35
+ <h3 id="in-progress-tickets">-</h3>
36
+ <p>In Progress</p>
37
+ </div>
38
+ </div>
39
+
40
+ <div class="stat-card">
41
+ <div class="stat-icon">✅</div>
42
+ <div class="stat-content">
43
+ <h3 id="resolved-tickets">-</h3>
44
+ <p>Resolved</p>
45
+ </div>
46
+ </div>
47
+ </div>
48
+
49
+ <!-- Filters and Controls -->
50
+ <div class="glass-card filters-section">
51
+ <div class="filters-header">
52
+ <h3>Ticket Filters</h3>
53
+ <button class="btn btn-primary" onclick="refreshTickets()">Refresh</button>
54
+ </div>
55
+
56
+ <div class="filters-row">
57
+ <div class="filter-group">
58
+ <label for="status-filter">Status:</label>
59
+ <select id="status-filter" onchange="applyFilters()">
60
+ <option value="">All Status</option>
61
+ <option value="open">Open</option>
62
+ <option value="in_progress">In Progress</option>
63
+ <option value="resolved">Resolved</option>
64
+ <option value="closed">Closed</option>
65
+ </select>
66
+ </div>
67
+
68
+ <div class="filter-group">
69
+ <label for="priority-filter">Priority:</label>
70
+ <select id="priority-filter" onchange="applyFilters()">
71
+ <option value="">All Priority</option>
72
+ <option value="low">Low</option>
73
+ <option value="medium">Medium</option>
74
+ <option value="high">High</option>
75
+ <option value="urgent">Urgent</option>
76
+ </select>
77
+ </div>
78
+
79
+ <div class="filter-group">
80
+ <label for="category-filter">Category:</label>
81
+ <select id="category-filter" onchange="applyFilters()">
82
+ <option value="">All Categories</option>
83
+ </select>
84
+ </div>
85
+ </div>
86
+ </div>
87
+
88
+ <!-- Tickets Table -->
89
+ <div class="glass-card tickets-table-section">
90
+ <div class="table-header">
91
+ <h3>All Tickets</h3>
92
+ <div class="pagination-info">
93
+ <span id="pagination-text">Loading...</span>
94
+ </div>
95
+ </div>
96
+
97
+ <div id="tickets-loading" class="loading-state">
98
+ <div class="spinner"></div>
99
+ <p>Loading tickets...</p>
100
+ </div>
101
+
102
+ <div id="tickets-table-container" style="display: none;">
103
+ <table id="tickets-table" class="admin-table">
104
+ <thead>
105
+ <tr>
106
+ <th>Ticket #</th>
107
+ <th>Customer</th>
108
+ <th>Subject</th>
109
+ <th>Category</th>
110
+ <th>Priority</th>
111
+ <th>Status</th>
112
+ <th>Assigned To</th>
113
+ <th>Created</th>
114
+ <th>Actions</th>
115
+ </tr>
116
+ </thead>
117
+ <tbody id="tickets-table-body">
118
+ </tbody>
119
+ </table>
120
+ </div>
121
+
122
+ <!-- Pagination -->
123
+ <div class="pagination-container">
124
+ <button id="prev-page" class="btn btn-outline" onclick="changePage(-1)" disabled>Previous</button>
125
+ <span id="page-info">Page 1 of 1</span>
126
+ <button id="next-page" class="btn btn-outline" onclick="changePage(1)" disabled>Next</button>
127
+ </div>
128
+ </div>
129
+ </div>
130
+
131
+ <!-- Ticket Detail Modal -->
132
+ <div id="ticket-detail-modal" class="modal" style="display: none;">
133
+ <div class="modal-content large-modal glass-card">
134
+ <div class="modal-header">
135
+ <h3 id="modal-ticket-title">Ticket Details</h3>
136
+ <button class="modal-close" onclick="closeTicketModal()">&times;</button>
137
+ </div>
138
+
139
+ <div class="modal-body">
140
+ <div id="ticket-detail-content"></div>
141
+
142
+ <!-- Admin Actions -->
143
+ <div class="admin-actions">
144
+ <h4>Admin Actions</h4>
145
+
146
+ <div class="action-row">
147
+ <div class="action-group">
148
+ <label for="assign-agent">Assign to Agent:</label>
149
+ <input type="text" id="assign-agent" placeholder="Agent name">
150
+ <button class="btn btn-secondary" onclick="assignTicket()">Assign</button>
151
+ </div>
152
+
153
+ <div class="action-group">
154
+ <label for="update-status">Update Status:</label>
155
+ <select id="update-status">
156
+ <option value="open">Open</option>
157
+ <option value="in_progress">In Progress</option>
158
+ <option value="resolved">Resolved</option>
159
+ <option value="closed">Closed</option>
160
+ </select>
161
+ <button class="btn btn-secondary" onclick="updateStatus()">Update</button>
162
+ </div>
163
+ </div>
164
+
165
+ <div class="admin-reply-section">
166
+ <h5>Add Admin Reply</h5>
167
+ <textarea id="admin-reply" placeholder="Type your reply..." rows="3"></textarea>
168
+ <div class="reply-options">
169
+ <label>
170
+ <input type="checkbox" id="internal-note"> Internal note (not visible to customer)
171
+ </label>
172
+ <button class="btn btn-primary" onclick="addAdminReply()">Send Reply</button>
173
+ </div>
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </div>
178
+ </div>
179
+
180
+ <style>
181
+ .admin-container {
182
+ max-width: 1400px;
183
+ margin: 0 auto;
184
+ padding: 2rem;
185
+ }
186
+
187
+ .page-header {
188
+ text-align: center;
189
+ margin-bottom: 3rem;
190
+ }
191
+
192
+ .page-title {
193
+ font-size: 2.5rem;
194
+ font-weight: 700;
195
+ color: white;
196
+ text-shadow: 0 2px 10px rgba(0,0,0,0.3);
197
+ margin-bottom: 0.5rem;
198
+ }
199
+
200
+ .page-subtitle {
201
+ font-size: 1.1rem;
202
+ color: rgba(255,255,255,0.9);
203
+ font-weight: 300;
204
+ }
205
+
206
+ .stats-grid {
207
+ display: grid;
208
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
209
+ gap: 1.5rem;
210
+ margin-bottom: 2rem;
211
+ }
212
+
213
+ .stat-card {
214
+ background: rgba(255, 255, 255, 0.15);
215
+ backdrop-filter: blur(25px);
216
+ border-radius: 15px;
217
+ border: 1px solid rgba(255, 255, 255, 0.2);
218
+ padding: 1.5rem;
219
+ display: flex;
220
+ align-items: center;
221
+ gap: 1rem;
222
+ transition: transform 0.3s ease;
223
+ }
224
+
225
+ .stat-card:hover {
226
+ transform: translateY(-2px);
227
+ }
228
+
229
+ .stat-icon {
230
+ font-size: 2rem;
231
+ }
232
+
233
+ .stat-content h3 {
234
+ font-size: 2rem;
235
+ font-weight: 700;
236
+ color: white;
237
+ margin: 0;
238
+ }
239
+
240
+ .stat-content p {
241
+ color: rgba(255,255,255,0.8);
242
+ margin: 0;
243
+ font-size: 0.9rem;
244
+ }
245
+
246
+ .glass-card {
247
+ background: rgba(255, 255, 255, 0.15);
248
+ backdrop-filter: blur(25px);
249
+ -webkit-backdrop-filter: blur(25px);
250
+ border-radius: 20px;
251
+ border: 1px solid rgba(255, 255, 255, 0.2);
252
+ padding: 2rem;
253
+ margin-bottom: 2rem;
254
+ box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
255
+ }
256
+
257
+ .filters-header {
258
+ display: flex;
259
+ justify-content: space-between;
260
+ align-items: center;
261
+ margin-bottom: 1.5rem;
262
+ }
263
+
264
+ .filters-header h3 {
265
+ color: white;
266
+ margin: 0;
267
+ }
268
+
269
+ .filters-row {
270
+ display: grid;
271
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
272
+ gap: 1rem;
273
+ }
274
+
275
+ .filter-group label {
276
+ display: block;
277
+ color: rgba(255,255,255,0.9);
278
+ margin-bottom: 0.5rem;
279
+ font-weight: 500;
280
+ }
281
+
282
+ .filter-group select,
283
+ .filter-group input {
284
+ width: 100%;
285
+ padding: 0.5rem;
286
+ border: 1px solid rgba(255,255,255,0.3);
287
+ border-radius: 8px;
288
+ background: rgba(255,255,255,0.1);
289
+ color: white;
290
+ font-size: 0.9rem;
291
+ }
292
+
293
+ .table-header {
294
+ display: flex;
295
+ justify-content: space-between;
296
+ align-items: center;
297
+ margin-bottom: 1.5rem;
298
+ }
299
+
300
+ .table-header h3 {
301
+ color: white;
302
+ margin: 0;
303
+ }
304
+
305
+ .admin-table {
306
+ width: 100%;
307
+ border-collapse: collapse;
308
+ background: rgba(255,255,255,0.1);
309
+ border-radius: 10px;
310
+ overflow: hidden;
311
+ }
312
+
313
+ .admin-table th,
314
+ .admin-table td {
315
+ padding: 1rem;
316
+ text-align: left;
317
+ border-bottom: 1px solid rgba(255,255,255,0.1);
318
+ }
319
+
320
+ .admin-table th {
321
+ background: rgba(255,255,255,0.2);
322
+ color: white;
323
+ font-weight: 600;
324
+ }
325
+
326
+ .admin-table td {
327
+ color: rgba(255,255,255,0.9);
328
+ }
329
+
330
+ .admin-table tr:hover {
331
+ background: rgba(255,255,255,0.1);
332
+ }
333
+
334
+ .ticket-status-badge {
335
+ padding: 0.25rem 0.75rem;
336
+ border-radius: 20px;
337
+ font-size: 0.8rem;
338
+ font-weight: 500;
339
+ text-transform: uppercase;
340
+ }
341
+
342
+ .priority-badge {
343
+ padding: 0.25rem 0.5rem;
344
+ border-radius: 15px;
345
+ font-size: 0.75rem;
346
+ font-weight: 500;
347
+ text-transform: uppercase;
348
+ }
349
+
350
+ .priority-low { background: #95a5a6; color: white; }
351
+ .priority-medium { background: #3498db; color: white; }
352
+ .priority-high { background: #f39c12; color: white; }
353
+ .priority-urgent { background: #e74c3c; color: white; }
354
+
355
+ .btn {
356
+ padding: 0.5rem 1rem;
357
+ border: none;
358
+ border-radius: 8px;
359
+ font-weight: 600;
360
+ text-decoration: none;
361
+ display: inline-block;
362
+ transition: all 0.3s ease;
363
+ cursor: pointer;
364
+ font-size: 0.9rem;
365
+ }
366
+
367
+ .btn-primary {
368
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
369
+ color: white;
370
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
371
+ }
372
+
373
+ .btn-secondary {
374
+ background: rgba(255,255,255,0.2);
375
+ color: white;
376
+ border: 1px solid rgba(255,255,255,0.3);
377
+ }
378
+
379
+ .btn-outline {
380
+ background: transparent;
381
+ color: white;
382
+ border: 1px solid rgba(255,255,255,0.3);
383
+ }
384
+
385
+ .btn:hover {
386
+ transform: translateY(-1px);
387
+ }
388
+
389
+ .btn:disabled {
390
+ opacity: 0.5;
391
+ cursor: not-allowed;
392
+ transform: none;
393
+ }
394
+
395
+ .pagination-container {
396
+ display: flex;
397
+ justify-content: space-between;
398
+ align-items: center;
399
+ margin-top: 1rem;
400
+ }
401
+
402
+ .loading-state {
403
+ text-align: center;
404
+ padding: 2rem;
405
+ color: rgba(255,255,255,0.8);
406
+ }
407
+
408
+ .spinner {
409
+ border: 3px solid rgba(255,255,255,0.3);
410
+ border-top: 3px solid white;
411
+ border-radius: 50%;
412
+ width: 40px;
413
+ height: 40px;
414
+ animation: spin 1s linear infinite;
415
+ margin: 0 auto 1rem;
416
+ }
417
+
418
+ @keyframes spin {
419
+ 0% { transform: rotate(0deg); }
420
+ 100% { transform: rotate(360deg); }
421
+ }
422
+
423
+ .modal {
424
+ position: fixed;
425
+ top: 0;
426
+ left: 0;
427
+ right: 0;
428
+ bottom: 0;
429
+ background: rgba(0,0,0,0.8);
430
+ display: flex;
431
+ justify-content: center;
432
+ align-items: center;
433
+ z-index: 2000;
434
+ }
435
+
436
+ .large-modal {
437
+ max-width: 900px;
438
+ width: 95%;
439
+ max-height: 90vh;
440
+ overflow-y: auto;
441
+ }
442
+
443
+ .modal-header {
444
+ display: flex;
445
+ justify-content: space-between;
446
+ align-items: center;
447
+ margin-bottom: 1.5rem;
448
+ }
449
+
450
+ .modal-close {
451
+ background: none;
452
+ border: none;
453
+ color: white;
454
+ font-size: 2rem;
455
+ cursor: pointer;
456
+ opacity: 0.7;
457
+ transition: opacity 0.3s ease;
458
+ }
459
+
460
+ .modal-close:hover {
461
+ opacity: 1;
462
+ }
463
+
464
+ .admin-actions {
465
+ margin-top: 2rem;
466
+ padding-top: 2rem;
467
+ border-top: 1px solid rgba(255,255,255,0.2);
468
+ }
469
+
470
+ .admin-actions h4,
471
+ .admin-actions h5 {
472
+ color: white;
473
+ margin-bottom: 1rem;
474
+ }
475
+
476
+ .action-row {
477
+ display: grid;
478
+ grid-template-columns: 1fr 1fr;
479
+ gap: 2rem;
480
+ margin-bottom: 2rem;
481
+ }
482
+
483
+ .action-group {
484
+ display: flex;
485
+ flex-direction: column;
486
+ gap: 0.5rem;
487
+ }
488
+
489
+ .action-group label {
490
+ color: rgba(255,255,255,0.9);
491
+ font-weight: 500;
492
+ }
493
+
494
+ .action-group input,
495
+ .action-group select {
496
+ padding: 0.5rem;
497
+ border: 1px solid rgba(255,255,255,0.3);
498
+ border-radius: 8px;
499
+ background: rgba(255,255,255,0.1);
500
+ color: white;
501
+ }
502
+
503
+ .admin-reply-section textarea {
504
+ width: 100%;
505
+ padding: 0.75rem;
506
+ border: 1px solid rgba(255,255,255,0.3);
507
+ border-radius: 8px;
508
+ background: rgba(255,255,255,0.1);
509
+ color: white;
510
+ resize: vertical;
511
+ margin-bottom: 1rem;
512
+ }
513
+
514
+ .reply-options {
515
+ display: flex;
516
+ justify-content: space-between;
517
+ align-items: center;
518
+ }
519
+
520
+ .reply-options label {
521
+ color: rgba(255,255,255,0.8);
522
+ display: flex;
523
+ align-items: center;
524
+ gap: 0.5rem;
525
+ }
526
+
527
+ @media (max-width: 768px) {
528
+ .stats-grid {
529
+ grid-template-columns: 1fr;
530
+ }
531
+
532
+ .filters-row {
533
+ grid-template-columns: 1fr;
534
+ }
535
+
536
+ .action-row {
537
+ grid-template-columns: 1fr;
538
+ }
539
+
540
+ .table-header {
541
+ flex-direction: column;
542
+ gap: 1rem;
543
+ text-align: center;
544
+ }
545
+
546
+ .admin-table {
547
+ font-size: 0.85rem;
548
+ }
549
+
550
+ .admin-table th,
551
+ .admin-table td {
552
+ padding: 0.5rem;
553
+ }
554
+ }
555
+ </style>
556
+
557
+ <script>
558
+ // Admin ticket management functionality
559
+ let currentPage = 1;
560
+ let totalPages = 1;
561
+ let currentFilters = {};
562
+ let currentTicketId = null;
563
+
564
+ // Initialize page
565
+ document.addEventListener('DOMContentLoaded', function() {
566
+ loadStats();
567
+ loadCategories();
568
+ loadTickets();
569
+ });
570
+
571
+ function loadStats() {
572
+ fetch('/api/admin/tickets/stats')
573
+ .then(response => response.json())
574
+ .then(data => {
575
+ if (data.success) {
576
+ const stats = data.stats.overall;
577
+ document.getElementById('total-tickets').textContent = stats.total_tickets;
578
+ document.getElementById('open-tickets').textContent = stats.open_tickets;
579
+ document.getElementById('in-progress-tickets').textContent = stats.in_progress_tickets;
580
+ document.getElementById('resolved-tickets').textContent = stats.resolved_tickets;
581
+ }
582
+ })
583
+ .catch(error => console.error('Error loading stats:', error));
584
+ }
585
+
586
+ function loadCategories() {
587
+ fetch('/api/tickets/categories')
588
+ .then(response => response.json())
589
+ .then(data => {
590
+ if (data.success) {
591
+ const categorySelect = document.getElementById('category-filter');
592
+ data.categories.forEach(category => {
593
+ const option = document.createElement('option');
594
+ option.value = category.name;
595
+ option.textContent = category.name;
596
+ categorySelect.appendChild(option);
597
+ });
598
+ }
599
+ })
600
+ .catch(error => console.error('Failed to load categories:', error));
601
+ }
602
+
603
+ function loadTickets(page = 1) {
604
+ currentPage = page;
605
+ document.getElementById('tickets-loading').style.display = 'block';
606
+ document.getElementById('tickets-table-container').style.display = 'none';
607
+
608
+ // Build query parameters
609
+ const params = new URLSearchParams({
610
+ page: page,
611
+ limit: 20,
612
+ ...currentFilters
613
+ });
614
+
615
+ fetch(`/api/admin/tickets?${params}`)
616
+ .then(response => response.json())
617
+ .then(data => {
618
+ document.getElementById('tickets-loading').style.display = 'none';
619
+
620
+ if (data.success) {
621
+ displayTickets(data.tickets);
622
+ updatePagination(data.pagination);
623
+ document.getElementById('tickets-table-container').style.display = 'block';
624
+ } else {
625
+ console.error('Failed to load tickets:', data.error);
626
+ }
627
+ })
628
+ .catch(error => {
629
+ document.getElementById('tickets-loading').style.display = 'none';
630
+ console.error('Error loading tickets:', error);
631
+ });
632
+ }
633
+
634
+ function displayTickets(tickets) {
635
+ const tbody = document.getElementById('tickets-table-body');
636
+ tbody.innerHTML = '';
637
+
638
+ tickets.forEach(ticket => {
639
+ const row = createTicketRow(ticket);
640
+ tbody.appendChild(row);
641
+ });
642
+ }
643
+
644
+ function createTicketRow(ticket) {
645
+ const tr = document.createElement('tr');
646
+ const createdDate = new Date(ticket.created_at).toLocaleDateString();
647
+
648
+ tr.innerHTML = `
649
+ <td><strong>${ticket.ticket_number}</strong></td>
650
+ <td>${ticket.first_name} ${ticket.last_name}<br><small>${ticket.email}</small></td>
651
+ <td>${ticket.subject}</td>
652
+ <td>${ticket.category}</td>
653
+ <td><span class="priority-badge priority-${ticket.priority}">${ticket.priority}</span></td>
654
+ <td><span class="ticket-status-badge status-${ticket.status}">${ticket.status.replace('_', ' ')}</span></td>
655
+ <td>${ticket.assigned_agent || 'Unassigned'}</td>
656
+ <td>${createdDate}</td>
657
+ <td>
658
+ <button class="btn btn-secondary" onclick="viewTicket('${ticket.ticket_number}')">View</button>
659
+ </td>
660
+ `;
661
+
662
+ return tr;
663
+ }
664
+
665
+ function updatePagination(pagination) {
666
+ totalPages = pagination.pages;
667
+ document.getElementById('page-info').textContent = `Page ${pagination.page} of ${pagination.pages}`;
668
+ document.getElementById('pagination-text').textContent =
669
+ `Showing ${((pagination.page - 1) * pagination.limit) + 1}-${Math.min(pagination.page * pagination.limit, pagination.total)} of ${pagination.total} tickets`;
670
+
671
+ document.getElementById('prev-page').disabled = pagination.page <= 1;
672
+ document.getElementById('next-page').disabled = pagination.page >= pagination.pages;
673
+ }
674
+
675
+ function changePage(direction) {
676
+ const newPage = currentPage + direction;
677
+ if (newPage >= 1 && newPage <= totalPages) {
678
+ loadTickets(newPage);
679
+ }
680
+ }
681
+
682
+ function applyFilters() {
683
+ currentFilters = {
684
+ status: document.getElementById('status-filter').value,
685
+ priority: document.getElementById('priority-filter').value,
686
+ category: document.getElementById('category-filter').value
687
+ };
688
+
689
+ // Remove empty filters
690
+ Object.keys(currentFilters).forEach(key => {
691
+ if (!currentFilters[key]) {
692
+ delete currentFilters[key];
693
+ }
694
+ });
695
+
696
+ loadTickets(1); // Reset to page 1 when filtering
697
+ }
698
+
699
+ function refreshTickets() {
700
+ loadStats();
701
+ loadTickets(currentPage);
702
+ }
703
+
704
+ function viewTicket(ticketNumber) {
705
+ fetch(`/api/tickets/${ticketNumber}`)
706
+ .then(response => response.json())
707
+ .then(data => {
708
+ if (data.success) {
709
+ showTicketDetails(data.ticket, data.updates);
710
+ currentTicketId = data.ticket.id;
711
+ document.getElementById('ticket-detail-modal').style.display = 'flex';
712
+ } else {
713
+ alert('Failed to load ticket details: ' + data.error);
714
+ }
715
+ })
716
+ .catch(error => {
717
+ console.error('Error loading ticket:', error);
718
+ alert('Error loading ticket details.');
719
+ });
720
+ }
721
+
722
+ function showTicketDetails(ticket, updates) {
723
+ const container = document.getElementById('ticket-detail-content');
724
+ const createdDate = new Date(ticket.created_at).toLocaleDateString();
725
+
726
+ let updatesHtml = '';
727
+ if (updates && updates.length > 0) {
728
+ updatesHtml = '<h4 style="color: white; margin-top: 2rem;">Updates:</h4>';
729
+ updates.forEach(update => {
730
+ const updateDate = new Date(update.created_at).toLocaleDateString();
731
+ const isInternal = update.is_internal ? ' (Internal)' : '';
732
+ updatesHtml += `
733
+ <div style="background: rgba(255,255,255,0.1); padding: 1rem; margin: 0.5rem 0; border-radius: 8px;">
734
+ <div style="color: rgba(255,255,255,0.8); font-size: 0.9rem; margin-bottom: 0.5rem;">
735
+ ${updateDate} - ${update.update_type}${isInternal}
736
+ </div>
737
+ <div style="color: white;">${update.message}</div>
738
+ </div>
739
+ `;
740
+ });
741
+ }
742
+
743
+ container.innerHTML = `
744
+ <div style="color: white;">
745
+ <h4>Ticket ${ticket.ticket_number}</h4>
746
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; margin: 1rem 0;">
747
+ <div>
748
+ <p><strong>Customer:</strong> ${ticket.first_name} ${ticket.last_name}</p>
749
+ <p><strong>Email:</strong> ${ticket.email}</p>
750
+ <p><strong>Status:</strong> <span class="ticket-status-badge status-${ticket.status}">${ticket.status.replace('_', ' ')}</span></p>
751
+ <p><strong>Priority:</strong> <span class="priority-badge priority-${ticket.priority}">${ticket.priority}</span></p>
752
+ </div>
753
+ <div>
754
+ <p><strong>Category:</strong> ${ticket.category}</p>
755
+ <p><strong>Assigned Agent:</strong> ${ticket.assigned_agent || 'Unassigned'}</p>
756
+ <p><strong>Created:</strong> ${createdDate}</p>
757
+ <p><strong>Escalation Level:</strong> ${ticket.escalation_level || 0}</p>
758
+ </div>
759
+ </div>
760
+ <h5 style="margin-top: 1.5rem;">Subject:</h5>
761
+ <p>${ticket.subject}</p>
762
+ <h5 style="margin-top: 1.5rem;">Description:</h5>
763
+ <p style="white-space: pre-wrap;">${ticket.description}</p>
764
+ ${updatesHtml}
765
+ </div>
766
+ `;
767
+
768
+ // Set current values in form fields
769
+ document.getElementById('assign-agent').value = ticket.assigned_agent || '';
770
+ document.getElementById('update-status').value = ticket.status;
771
+
772
+ document.getElementById('modal-ticket-title').textContent = `Ticket ${ticket.ticket_number}`;
773
+ }
774
+
775
+ function assignTicket() {
776
+ if (!currentTicketId) return;
777
+
778
+ const agentName = document.getElementById('assign-agent').value.trim();
779
+ if (!agentName) {
780
+ alert('Please enter an agent name');
781
+ return;
782
+ }
783
+
784
+ fetch(`/api/admin/tickets/${currentTicketId}/assign`, {
785
+ method: 'PUT',
786
+ headers: { 'Content-Type': 'application/json' },
787
+ body: JSON.stringify({ assigned_agent: agentName })
788
+ })
789
+ .then(response => response.json())
790
+ .then(data => {
791
+ if (data.success) {
792
+ alert('Ticket assigned successfully!');
793
+ refreshTickets();
794
+ closeTicketModal();
795
+ } else {
796
+ alert('Failed to assign ticket: ' + data.error);
797
+ }
798
+ })
799
+ .catch(error => {
800
+ console.error('Error assigning ticket:', error);
801
+ alert('Error assigning ticket. Please try again.');
802
+ });
803
+ }
804
+
805
+ function updateStatus() {
806
+ if (!currentTicketId) return;
807
+
808
+ const newStatus = document.getElementById('update-status').value;
809
+ const resolutionNotes = newStatus === 'resolved' ?
810
+ prompt('Resolution notes (optional):') || '' : '';
811
+
812
+ fetch(`/api/admin/tickets/${currentTicketId}/status`, {
813
+ method: 'PUT',
814
+ headers: { 'Content-Type': 'application/json' },
815
+ body: JSON.stringify({
816
+ status: newStatus,
817
+ resolution_notes: resolutionNotes
818
+ })
819
+ })
820
+ .then(response => response.json())
821
+ .then(data => {
822
+ if (data.success) {
823
+ alert('Status updated successfully!');
824
+ refreshTickets();
825
+ closeTicketModal();
826
+ } else {
827
+ alert('Failed to update status: ' + data.error);
828
+ }
829
+ })
830
+ .catch(error => {
831
+ console.error('Error updating status:', error);
832
+ alert('Error updating status. Please try again.');
833
+ });
834
+ }
835
+
836
+ function addAdminReply() {
837
+ if (!currentTicketId) return;
838
+
839
+ const message = document.getElementById('admin-reply').value.trim();
840
+ const isInternal = document.getElementById('internal-note').checked;
841
+
842
+ if (!message) {
843
+ alert('Please enter a message');
844
+ return;
845
+ }
846
+
847
+ fetch(`/api/admin/tickets/${currentTicketId}/reply`, {
848
+ method: 'POST',
849
+ headers: { 'Content-Type': 'application/json' },
850
+ body: JSON.stringify({
851
+ message: message,
852
+ is_internal: isInternal
853
+ })
854
+ })
855
+ .then(response => response.json())
856
+ .then(data => {
857
+ if (data.success) {
858
+ alert('Reply added successfully!');
859
+ document.getElementById('admin-reply').value = '';
860
+ document.getElementById('internal-note').checked = false;
861
+ // Reload ticket details
862
+ const ticketNumber = document.getElementById('modal-ticket-title').textContent.replace('Ticket ', '');
863
+ viewTicket(ticketNumber);
864
+ } else {
865
+ alert('Failed to add reply: ' + data.error);
866
+ }
867
+ })
868
+ .catch(error => {
869
+ console.error('Error adding reply:', error);
870
+ alert('Error adding reply. Please try again.');
871
+ });
872
+ }
873
+
874
+ function closeTicketModal() {
875
+ document.getElementById('ticket-detail-modal').style.display = 'none';
876
+ document.getElementById('admin-reply').value = '';
877
+ document.getElementById('internal-note').checked = false;
878
+ currentTicketId = null;
879
+ }
880
+
881
+ // Close modal on outside click
882
+ document.getElementById('ticket-detail-modal').addEventListener('click', function(e) {
883
+ if (e.target === this) {
884
+ closeTicketModal();
885
+ }
886
+ });
887
+ </script>
888
+ {% endblock %}
templates/base.html ADDED
The diff for this file is too large to render. See raw diff
 
templates/chat.html ADDED
@@ -0,0 +1,676 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Live Chat - Too Many Cables{% endblock %}
4
+
5
+ {% block content %}
6
+ <!-- Page Header -->
7
+ <section class="page-header">
8
+ <div class="container">
9
+ <div class="header-card">
10
+ <div class="page-header-content">
11
+ <h1>Live Chat Support</h1>
12
+ <p>Get instant help from our AI-powered customer service agent</p>
13
+ <div class="status-indicator">
14
+ <div id="status-dot" class="status-dot online"></div>
15
+ <span id="status-text">Agent Online</span>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </section>
21
+
22
+ <!-- Chat Interface -->
23
+ <section class="chat-section">
24
+ <div class="container">
25
+ <div class="chat-layout">
26
+ <!-- Main Chat Container -->
27
+ <div class="glassmorphism-container chat-main">
28
+ <div class="chat-container">
29
+ <div id="chat-messages" class="chat-messages">
30
+ <div class="welcome-message">
31
+ <div class="agent-avatar">🤖</div>
32
+ <div class="message-content">
33
+ <h4>Hi! I'm TMCBot</h4>
34
+ <p>I'm here to help you find the perfect cables and accessories. Ask me about products, compatibility, or any technical questions!</p>
35
+ <div id="welcome-tickets-info" style="display: none;">
36
+ <p><strong>I can see you have active support tickets. Feel free to ask me about them!</strong></p>
37
+ </div>
38
+ </div>
39
+ </div>
40
+ </div>
41
+
42
+ <div class="typing-indicator" id="typing-indicator" style="display: none;">
43
+ <div class="typing-dots">
44
+ <span></span>
45
+ <span></span>
46
+ <span></span>
47
+ </div>
48
+ <span>AI agent is typing...</span>
49
+ </div>
50
+
51
+ <form id="chat-form" class="chat-input-form" onsubmit="event.preventDefault(); return false;" novalidate>
52
+ <div class="input-group">
53
+ <textarea
54
+ id="message-input"
55
+ placeholder="Type your message here..."
56
+ rows="1"
57
+ maxlength="1000"
58
+ ></textarea>
59
+ <button type="submit" id="send-button" class="send-button" disabled>
60
+ <span class="send-icon">➤</span>
61
+ </button>
62
+ <button type="button" id="clear-chat" class="action-button clear-chat" title="Clear Chat History">
63
+ Clear
64
+ </button>
65
+ <button type="button" id="create-ticket-button" class="action-button" title="Create Support Ticket">
66
+ Create Ticket
67
+ </button>
68
+ <button type="button" id="end-conversation-button" class="action-button end-conversation" title="End Conversation & Save Summary">
69
+ End Chat
70
+ </button>
71
+ </div>
72
+ </form>
73
+ </div>
74
+ </div>
75
+
76
+ <!-- Ticket Sidebar -->
77
+ <div class="glassmorphism-container ticket-sidebar" id="ticket-sidebar">
78
+ <div class="sidebar-header">
79
+ <h3>Your Tickets</h3>
80
+ <button id="toggle-sidebar" class="toggle-button">↔</button>
81
+ </div>
82
+
83
+ <div id="user-tickets-loading" class="loading-state" style="display: none;">
84
+ <div class="spinner-small"></div>
85
+ <p>Loading tickets...</p>
86
+ </div>
87
+
88
+ <div id="no-tickets" class="no-tickets-state">
89
+ <p>No active tickets</p>
90
+ <button class="btn btn-primary" onclick="showCreateTicketModal()">Create Ticket</button>
91
+ </div>
92
+
93
+ <div id="user-tickets-list" class="tickets-list"></div>
94
+
95
+ <div class="sidebar-actions">
96
+ <button class="btn btn-outline" onclick="refreshUserTickets()">Refresh</button>
97
+ <button class="btn btn-primary" onclick="showCreateTicketModal()">New Ticket</button>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ </section>
103
+
104
+ <!-- Create Ticket Modal -->
105
+ <div id="create-ticket-modal" class="modal" style="display: none;">
106
+ <div class="modal-content glassmorphism-container">
107
+ <div class="modal-header">
108
+ <h3>Create Support Ticket</h3>
109
+ <button class="modal-close" onclick="closeCreateTicketModal()">&times;</button>
110
+ </div>
111
+
112
+ <form id="create-ticket-form" class="modal-body">
113
+ <div class="form-group">
114
+ <label for="ticket-subject">Subject *</label>
115
+ <input type="text" id="ticket-subject" placeholder="Brief description of your issue" required>
116
+ </div>
117
+
118
+ <div class="form-group">
119
+ <label for="ticket-category">Category</label>
120
+ <select id="ticket-category">
121
+ <option value="General">General Support</option>
122
+ <option value="Technical">Technical Issue</option>
123
+ <option value="Product">Product Question</option>
124
+ <option value="Billing">Billing</option>
125
+ <option value="Shipping">Shipping & Delivery</option>
126
+ </select>
127
+ </div>
128
+
129
+ <div class="form-group">
130
+ <label for="ticket-priority">Priority</label>
131
+ <select id="ticket-priority">
132
+ <option value="low">Low</option>
133
+ <option value="medium" selected>Medium</option>
134
+ <option value="high">High</option>
135
+ <option value="urgent">Urgent</option>
136
+ </select>
137
+ </div>
138
+
139
+ <div class="form-group">
140
+ <label for="ticket-description">Description *</label>
141
+ <textarea id="ticket-description" rows="4" placeholder="Please describe your issue in detail..." required></textarea>
142
+ </div>
143
+
144
+ <div class="form-group">
145
+ <label>
146
+ <input type="checkbox" id="include-chat-context" checked>
147
+ Include recent chat conversation in ticket
148
+ </label>
149
+ </div>
150
+
151
+ <div class="modal-actions">
152
+ <button type="button" class="btn btn-outline" onclick="closeCreateTicketModal()">Cancel</button>
153
+ <button type="submit" class="btn btn-primary">Create Ticket</button>
154
+ </div>
155
+ </form>
156
+ </div>
157
+ </div>
158
+ {% endblock %}
159
+
160
+ {% block extra_styles %}
161
+ <style>
162
+ /* Chat Layout with Sidebar */
163
+ .chat-layout {
164
+ display: grid;
165
+ grid-template-columns: 1fr 320px;
166
+ gap: 2rem;
167
+ max-width: 1400px;
168
+ margin: 0 auto;
169
+ }
170
+
171
+ .chat-main {
172
+ min-height: 600px;
173
+ }
174
+
175
+ .ticket-sidebar {
176
+ background: rgba(255, 255, 255, 0.12);
177
+ padding: 1.5rem;
178
+ height: fit-content;
179
+ max-height: 80vh;
180
+ overflow-y: auto;
181
+ }
182
+
183
+ .sidebar-header {
184
+ display: flex;
185
+ justify-content: space-between;
186
+ align-items: center;
187
+ margin-bottom: 1rem;
188
+ padding-bottom: 0.5rem;
189
+ border-bottom: 1px solid rgba(255,255,255,0.2);
190
+ }
191
+
192
+ .sidebar-header h3 {
193
+ color: white;
194
+ margin: 0;
195
+ font-size: 1.2rem;
196
+ }
197
+
198
+ .toggle-button {
199
+ background: rgba(255,255,255,0.2);
200
+ border: none;
201
+ color: white;
202
+ padding: 0.25rem 0.5rem;
203
+ border-radius: 4px;
204
+ cursor: pointer;
205
+ }
206
+
207
+ .loading-state {
208
+ text-align: center;
209
+ padding: 2rem;
210
+ color: rgba(255,255,255,0.8);
211
+ }
212
+
213
+ .spinner-small {
214
+ border: 2px solid rgba(255,255,255,0.3);
215
+ border-top: 2px solid white;
216
+ border-radius: 50%;
217
+ width: 20px;
218
+ height: 20px;
219
+ animation: spin 1s linear infinite;
220
+ margin: 0 auto 0.5rem;
221
+ }
222
+
223
+ .no-tickets-state {
224
+ text-align: center;
225
+ padding: 2rem 1rem;
226
+ color: rgba(255,255,255,0.8);
227
+ }
228
+
229
+ .tickets-list {
230
+ max-height: 400px;
231
+ overflow-y: auto;
232
+ }
233
+
234
+ .ticket-item {
235
+ background: rgba(255,255,255,0.1);
236
+ border: 1px solid rgba(255,255,255,0.2);
237
+ border-radius: 8px;
238
+ padding: 1rem;
239
+ margin-bottom: 0.5rem;
240
+ cursor: pointer;
241
+ transition: all 0.3s ease;
242
+ }
243
+
244
+ .ticket-item:hover {
245
+ background: rgba(255,255,255,0.15);
246
+ transform: translateY(-1px);
247
+ }
248
+
249
+ .ticket-item h4 {
250
+ color: white;
251
+ font-size: 0.9rem;
252
+ margin: 0 0 0.5rem 0;
253
+ }
254
+
255
+ .ticket-item p {
256
+ color: rgba(255,255,255,0.8);
257
+ font-size: 0.8rem;
258
+ margin: 0.25rem 0;
259
+ }
260
+
261
+ .ticket-status {
262
+ display: inline-block;
263
+ padding: 0.2rem 0.5rem;
264
+ border-radius: 10px;
265
+ font-size: 0.7rem;
266
+ font-weight: 500;
267
+ text-transform: uppercase;
268
+ }
269
+
270
+ .status-open { background: rgba(52, 152, 219, 0.8); color: white; }
271
+ .status-in_progress { background: rgba(241, 196, 15, 0.8); color: white; }
272
+ .status-resolved { background: rgba(46, 204, 113, 0.8); color: white; }
273
+
274
+ .sidebar-actions {
275
+ margin-top: 1rem;
276
+ padding-top: 1rem;
277
+ border-top: 1px solid rgba(255,255,255,0.2);
278
+ display: flex;
279
+ gap: 0.5rem;
280
+ }
281
+
282
+ .sidebar-actions .btn {
283
+ flex: 1;
284
+ padding: 0.5rem;
285
+ font-size: 0.8rem;
286
+ }
287
+
288
+ /* Enhanced Input Group */
289
+ .input-group {
290
+ position: relative;
291
+ display: flex;
292
+ align-items: flex-end;
293
+ gap: 0.5rem;
294
+ }
295
+
296
+ .action-button {
297
+ background: rgba(255, 255, 255, 0.2);
298
+ border: 1px solid rgba(255, 255, 255, 0.3);
299
+ color: white;
300
+ padding: 0.75rem;
301
+ border-radius: 10px;
302
+ cursor: pointer;
303
+ font-size: 1.1rem;
304
+ transition: all 0.3s ease;
305
+ min-width: 44px;
306
+ height: 44px;
307
+ display: flex;
308
+ align-items: center;
309
+ justify-content: center;
310
+ }
311
+
312
+ .action-button:hover {
313
+ background: rgba(255, 255, 255, 0.3);
314
+ transform: translateY(-1px);
315
+ }
316
+
317
+ /* Modal Styles */
318
+ .modal {
319
+ position: fixed;
320
+ top: 0;
321
+ left: 0;
322
+ right: 0;
323
+ bottom: 0;
324
+ background: rgba(0,0,0,0.8);
325
+ display: flex;
326
+ justify-content: center;
327
+ align-items: center;
328
+ z-index: 2000;
329
+ }
330
+
331
+ .modal-content {
332
+ max-width: 500px;
333
+ width: 95%;
334
+ max-height: 80vh;
335
+ overflow-y: auto;
336
+ padding: 2rem;
337
+ }
338
+
339
+ .modal-header {
340
+ display: flex;
341
+ justify-content: space-between;
342
+ align-items: center;
343
+ margin-bottom: 1.5rem;
344
+ }
345
+
346
+ .modal-header h3 {
347
+ color: white;
348
+ margin: 0;
349
+ }
350
+
351
+ .modal-close {
352
+ background: none;
353
+ border: none;
354
+ color: white;
355
+ font-size: 1.5rem;
356
+ cursor: pointer;
357
+ opacity: 0.7;
358
+ transition: opacity 0.3s ease;
359
+ }
360
+
361
+ .modal-close:hover {
362
+ opacity: 1;
363
+ }
364
+
365
+ .form-group {
366
+ margin-bottom: 1rem;
367
+ }
368
+
369
+ .form-group label {
370
+ display: block;
371
+ color: rgba(255,255,255,0.9);
372
+ margin-bottom: 0.5rem;
373
+ font-weight: 500;
374
+ }
375
+
376
+ .form-group input,
377
+ .form-group select,
378
+ .form-group textarea {
379
+ width: 100%;
380
+ padding: 0.75rem;
381
+ border: 1px solid rgba(255,255,255,0.3);
382
+ border-radius: 8px;
383
+ background: rgba(255,255,255,0.1);
384
+ color: white;
385
+ font-size: 0.9rem;
386
+ }
387
+
388
+ .form-group input::placeholder,
389
+ .form-group textarea::placeholder {
390
+ color: rgba(255,255,255,0.6);
391
+ }
392
+
393
+ .form-group input[type="checkbox"] {
394
+ width: auto;
395
+ margin-right: 0.5rem;
396
+ }
397
+
398
+ .modal-actions {
399
+ display: flex;
400
+ gap: 1rem;
401
+ justify-content: flex-end;
402
+ margin-top: 2rem;
403
+ }
404
+
405
+ .btn {
406
+ padding: 0.75rem 1.5rem;
407
+ border: none;
408
+ border-radius: 8px;
409
+ font-weight: 600;
410
+ cursor: pointer;
411
+ transition: all 0.3s ease;
412
+ }
413
+
414
+ .btn-primary {
415
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
416
+ color: white;
417
+ }
418
+
419
+ .btn-outline {
420
+ background: transparent;
421
+ color: white;
422
+ border: 1px solid rgba(255,255,255,0.3);
423
+ }
424
+
425
+ .btn:hover {
426
+ transform: translateY(-1px);
427
+ }
428
+
429
+ /* Responsive Design */
430
+ @media (max-width: 768px) {
431
+ .chat-layout {
432
+ grid-template-columns: 1fr;
433
+ }
434
+
435
+ .ticket-sidebar {
436
+ order: -1;
437
+ max-height: 300px;
438
+ }
439
+
440
+ .sidebar-actions {
441
+ flex-direction: column;
442
+ }
443
+
444
+ .modal-content {
445
+ margin: 1rem;
446
+ padding: 1.5rem;
447
+ }
448
+
449
+ .modal-actions {
450
+ flex-direction: column;
451
+ }
452
+ }
453
+
454
+ /* Sidebar collapsed state */
455
+ .ticket-sidebar.collapsed {
456
+ width: 60px;
457
+ padding: 1rem 0.5rem;
458
+ }
459
+
460
+ .ticket-sidebar.collapsed .sidebar-header h3,
461
+ .ticket-sidebar.collapsed .tickets-list,
462
+ .ticket-sidebar.collapsed .sidebar-actions,
463
+ .ticket-sidebar.collapsed .no-tickets-state {
464
+ display: none;
465
+ }
466
+ </style>
467
+ {% endblock %}
468
+
469
+ {% block extra_scripts %}
470
+ <script src="{{ url_for('static', filename='chat.js') }}?v={{ cache_bust }}"></script>
471
+ <script>
472
+ // Global variables for ticket integration
473
+ let currentConversationId = null;
474
+ let userTickets = [];
475
+
476
+ document.addEventListener('DOMContentLoaded', function() {
477
+ // Auto-resize textarea
478
+ const messageInput = document.getElementById('message-input');
479
+ messageInput.addEventListener('input', function() {
480
+ this.style.height = 'auto';
481
+ this.style.height = Math.min(this.scrollHeight, 120) + 'px';
482
+
483
+ // Enable/disable send button
484
+ const sendButton = document.getElementById('send-button');
485
+ sendButton.disabled = this.value.trim().length === 0;
486
+ });
487
+
488
+ // Load user tickets if logged in
489
+ loadUserTickets();
490
+
491
+ // Set up create ticket form
492
+ setupCreateTicketModal();
493
+ });
494
+
495
+ function loadUserTickets() {
496
+ const loading = document.getElementById('user-tickets-loading');
497
+ const noTickets = document.getElementById('no-tickets');
498
+ const ticketsList = document.getElementById('user-tickets-list');
499
+
500
+ loading.style.display = 'block';
501
+ noTickets.style.display = 'none';
502
+ ticketsList.innerHTML = '';
503
+
504
+ fetch('/api/chat/user-tickets')
505
+ .then(response => response.json())
506
+ .then(data => {
507
+ loading.style.display = 'none';
508
+
509
+ if (data.success && data.tickets.length > 0) {
510
+ userTickets = data.tickets;
511
+ displayUserTickets(data.tickets);
512
+
513
+ // Show ticket info in welcome message
514
+ const welcomeTicketsInfo = document.getElementById('welcome-tickets-info');
515
+ if (welcomeTicketsInfo) {
516
+ welcomeTicketsInfo.style.display = 'block';
517
+ }
518
+ } else {
519
+ noTickets.style.display = 'block';
520
+ }
521
+ })
522
+ .catch(error => {
523
+ loading.style.display = 'none';
524
+ noTickets.style.display = 'block';
525
+ console.error('Error loading user tickets:', error);
526
+ });
527
+ }
528
+
529
+ function displayUserTickets(tickets) {
530
+ const ticketsList = document.getElementById('user-tickets-list');
531
+ ticketsList.innerHTML = '';
532
+
533
+ tickets.forEach(ticket => {
534
+ const ticketElement = createTicketElement(ticket);
535
+ ticketsList.appendChild(ticketElement);
536
+ });
537
+ }
538
+
539
+ function createTicketElement(ticket) {
540
+ const div = document.createElement('div');
541
+ div.className = 'ticket-item';
542
+ div.onclick = () => viewTicketInChat(ticket);
543
+
544
+ const createdDate = new Date(ticket.created_at).toLocaleDateString();
545
+
546
+ div.innerHTML = `
547
+ <h4>#${ticket.number}: ${ticket.subject}</h4>
548
+ <p><span class="ticket-status status-${ticket.status}">${ticket.status.replace('_', ' ')}</span></p>
549
+ <p><strong>Category:</strong> ${ticket.category}</p>
550
+ <p><strong>Priority:</strong> ${ticket.priority}</p>
551
+ <p><strong>Created:</strong> ${createdDate}</p>
552
+ ${ticket.assigned_agent ? `<p><strong>Agent:</strong> ${ticket.assigned_agent}</p>` : ''}
553
+ `;
554
+
555
+ return div;
556
+ }
557
+
558
+ function viewTicketInChat(ticket) {
559
+ // Add ticket info to chat
560
+ const ticketMessage = `I'd like to discuss my ticket #${ticket.number}: "${ticket.subject}". Status: ${ticket.status}, Priority: ${ticket.priority}`;
561
+
562
+ const messageInput = document.getElementById('message-input');
563
+ messageInput.value = ticketMessage;
564
+ messageInput.focus();
565
+
566
+ // Trigger input event to enable send button
567
+ messageInput.dispatchEvent(new Event('input'));
568
+ }
569
+
570
+ function refreshUserTickets() {
571
+ loadUserTickets();
572
+ }
573
+
574
+ function showCreateTicketModal() {
575
+ document.getElementById('create-ticket-modal').style.display = 'flex';
576
+ }
577
+
578
+ function closeCreateTicketModal() {
579
+ document.getElementById('create-ticket-modal').style.display = 'none';
580
+ document.getElementById('create-ticket-form').reset();
581
+ }
582
+
583
+ function setupCreateTicketModal() {
584
+ const form = document.getElementById('create-ticket-form');
585
+
586
+ form.addEventListener('submit', function(e) {
587
+ e.preventDefault();
588
+
589
+ const subject = document.getElementById('ticket-subject').value.trim();
590
+ const description = document.getElementById('ticket-description').value.trim();
591
+ const category = document.getElementById('ticket-category').value;
592
+ const priority = document.getElementById('ticket-priority').value;
593
+ const includeChat = document.getElementById('include-chat-context').checked;
594
+
595
+ if (!subject || !description) {
596
+ alert('Please fill in all required fields');
597
+ return;
598
+ }
599
+
600
+ const ticketData = {
601
+ subject,
602
+ description,
603
+ category,
604
+ priority,
605
+ conversation_id: includeChat ? currentConversationId : null
606
+ };
607
+
608
+ const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
609
+
610
+ fetch('/api/chat/create-ticket', {
611
+ method: 'POST',
612
+ headers: {
613
+ 'Content-Type': 'application/json',
614
+ 'X-CSRFToken': csrfToken
615
+ },
616
+ body: JSON.stringify(ticketData)
617
+ })
618
+ .then(response => response.json())
619
+ .then(data => {
620
+ if (data.success) {
621
+ alert(data.message);
622
+ closeCreateTicketModal();
623
+ loadUserTickets(); // Refresh ticket list
624
+
625
+ // Add success message to chat
626
+ addMessageToChat('system', `✅ ${data.message}`);
627
+ } else {
628
+ alert('Failed to create ticket: ' + data.error);
629
+ }
630
+ })
631
+ .catch(error => {
632
+ console.error('Error creating ticket:', error);
633
+ alert('Error creating ticket. Please try again.');
634
+ });
635
+ });
636
+ }
637
+
638
+ // Update conversation ID when chat starts
639
+ function updateConversationId(conversationId) {
640
+ currentConversationId = conversationId;
641
+ }
642
+
643
+ // Add message to chat (utility function)
644
+ function addMessageToChat(role, content) {
645
+ const chatMessages = document.getElementById('chat-messages');
646
+ const messageDiv = document.createElement('div');
647
+ messageDiv.className = `message ${role}-message`;
648
+
649
+ if (role === 'system') {
650
+ messageDiv.innerHTML = `
651
+ <div class="system-message">
652
+ <div class="message-content">
653
+ ${content}
654
+ </div>
655
+ </div>
656
+ `;
657
+ }
658
+
659
+ chatMessages.appendChild(messageDiv);
660
+ chatMessages.scrollTop = chatMessages.scrollHeight;
661
+ }
662
+
663
+ // Toggle sidebar
664
+ document.getElementById('toggle-sidebar').addEventListener('click', function() {
665
+ const sidebar = document.getElementById('ticket-sidebar');
666
+ sidebar.classList.toggle('collapsed');
667
+ });
668
+
669
+ // Close modal on outside click
670
+ document.getElementById('create-ticket-modal').addEventListener('click', function(e) {
671
+ if (e.target === this) {
672
+ closeCreateTicketModal();
673
+ }
674
+ });
675
+ </script>
676
+ {% endblock %}
templates/contact.html ADDED
File without changes
templates/homepage.html ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Too Many Cables - Premium Cables & Tech Accessories{% endblock %}
4
+
5
+ {% block content %}
6
+ <!-- Hero Section -->
7
+ <section class="hero">
8
+ <div class="hero-container">
9
+ <div class="hero-content">
10
+ <h1 class="hero-title">Premium Cables for Every Connection</h1>
11
+ <p class="hero-subtitle">From USB-C to HDMI, we've got the high-quality cables and accessories you need. Fast shipping, lifetime warranty, and 24/7 support.</p>
12
+ <div class="hero-actions">
13
+ <a href="{{ url_for('products') }}" class="btn btn-primary btn-large">Shop Now</a>
14
+ <a href="#" class="btn btn-outline btn-large chat-trigger-btn">Get Help 💬</a>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ </section>
19
+
20
+ <!-- Features Section -->
21
+ <section class="features">
22
+ <div class="container">
23
+ <h2 class="section-title">Why Choose Too Many Cables?</h2>
24
+ <div class="features-grid">
25
+ <div class="feature-card">
26
+ <div class="feature-icon">⚡</div>
27
+ <h3>Fast & Reliable</h3>
28
+ <p>High-speed data transfer and charging with premium materials and gold-plated connectors.</p>
29
+ </div>
30
+ <div class="feature-card">
31
+ <div class="feature-icon">🛡️</div>
32
+ <h3>Lifetime Warranty</h3>
33
+ <p>We stand behind our products with a comprehensive lifetime warranty on all cables.</p>
34
+ </div>
35
+ <div class="feature-card">
36
+ <div class="feature-icon">🚚</div>
37
+ <h3>Fast Shipping</h3>
38
+ <p>Free shipping on orders over $25. Most orders ship same day and arrive within 2-3 business days.</p>
39
+ </div>
40
+ <div class="feature-card">
41
+ <div class="feature-icon">💬</div>
42
+ <h3>24/7 Support</h3>
43
+ <p>Get instant help with our AI-powered chat support, available 24/7 for all your questions.</p>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ </section>
48
+
49
+ <!-- Popular Products Section -->
50
+ <section class="popular-products">
51
+ <div class="container">
52
+ <h2 class="section-title">Popular Products</h2>
53
+ <div class="products-grid">
54
+ <div class="product-card">
55
+ <div class="product-image">🔌</div>
56
+ <h3>USB-C to USB-C Cable</h3>
57
+ <p class="product-description">60W fast charging, 10Gbps data transfer, 6ft length</p>
58
+ <div class="product-price">$19.99</div>
59
+ <div class="product-rating">⭐⭐⭐⭐⭐ (1,247 reviews)</div>
60
+ <button class="btn btn-primary" onclick="showProductDetails('usb-c-cable')">More Details</button>
61
+ </div>
62
+ <div class="product-card">
63
+ <div class="product-image">📺</div>
64
+ <h3>4K HDMI Cable</h3>
65
+ <p class="product-description">8K@60Hz, 4K@120Hz, HDR10+, 10ft premium cable</p>
66
+ <div class="product-price">$24.99</div>
67
+ <div class="product-rating">⭐⭐⭐⭐⭐ (856 reviews)</div>
68
+ <button class="btn btn-primary" onclick="showProductDetails('4k-hdmi-cable')">More Details</button>
69
+ </div>
70
+ <div class="product-card">
71
+ <div class="product-image">🔋</div>
72
+ <h3>Multi-Port Charging Hub</h3>
73
+ <p class="product-description">6 ports, 100W total, USB-C PD, smart charging</p>
74
+ <div class="product-price">$49.99</div>
75
+ <div class="product-rating">⭐⭐⭐⭐⭐ (692 reviews)</div>
76
+ <button class="btn btn-primary" onclick="showProductDetails('charging-hub')">More Details</button>
77
+ </div>
78
+ <div class="product-card">
79
+ <div class="product-image">🔗</div>
80
+ <h3>USB-C Hub Adapter</h3>
81
+ <p class="product-description">7-in-1 hub with HDMI, USB-A, SD card, Ethernet</p>
82
+ <div class="product-price">$34.99</div>
83
+ <div class="product-rating">⭐⭐⭐⭐⭐ (1,104 reviews)</div>
84
+ <button class="btn btn-primary" onclick="showProductDetails('usb-c-hub')">More Details</button>
85
+ </div>
86
+ </div>
87
+ <div class="section-cta">
88
+ <a href="{{ url_for('products') }}" class="btn btn-outline">View All Products</a>
89
+ </div>
90
+ </div>
91
+ </section>
92
+
93
+ <!-- Customer Support CTA -->
94
+ <section class="support-cta">
95
+ <div class="container">
96
+ <div class="cta-content">
97
+ <h2>Need Help Choosing the Right Cable?</h2>
98
+ <p>Our AI-powered customer service is available 24/7 to help you find the perfect solution for your needs.</p>
99
+ <div class="cta-actions">
100
+ <a href="#" class="btn btn-primary btn-large chat-trigger-btn">Start Live Chat 💬</a>
101
+ <a href="{{ url_for('products') }}" class="btn btn-outline btn-large">Browse Products</a>
102
+ </div>
103
+ </div>
104
+ <div class="cta-features">
105
+ <div class="cta-feature">
106
+ <span class="feature-icon">🤖</span>
107
+ <span>AI-Powered Support</span>
108
+ </div>
109
+ <div class="cta-feature">
110
+ <span class="feature-icon">⚡</span>
111
+ <span>Instant Responses</span>
112
+ </div>
113
+ <div class="cta-feature">
114
+ <span class="feature-icon">🎯</span>
115
+ <span>Personalized Recommendations</span>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ </section>
120
+
121
+ <!-- Customer Reviews Section -->
122
+ <section class="reviews">
123
+ <div class="container">
124
+ <h2 class="section-title">What Our Customers Say</h2>
125
+ <div class="reviews-grid">
126
+ <div class="review-card">
127
+ <div class="review-rating">⭐⭐⭐⭐⭐</div>
128
+ <p class="review-text">"Amazing quality cables! My USB-C cable has been working perfectly for over a year now. The customer service chat helped me choose the right one."</p>
129
+ <div class="review-author">- Sarah M., Software Developer</div>
130
+ </div>
131
+ <div class="review-card">
132
+ <div class="review-rating">⭐⭐⭐⭐⭐</div>
133
+ <p class="review-text">"Fast shipping and great prices. The HDMI cable works flawlessly with my 4K monitor. Will definitely order again!"</p>
134
+ <div class="review-author">- Mike R., Graphic Designer</div>
135
+ </div>
136
+ <div class="review-card">
137
+ <div class="review-rating">⭐⭐⭐⭐⭐</div>
138
+ <p class="review-text">"The AI chat support is incredible! Got help immediately at 2AM when I needed to find a specific adapter. Highly recommend!"</p>
139
+ <div class="review-author">- Jennifer L., Marketing Manager</div>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </section>
144
+
145
+ <!-- Product Details Modal -->
146
+ <div id="product-details-modal" class="modal" style="display: none;">
147
+ <div class="modal-content">
148
+ <div class="modal-header">
149
+ <h2 id="product-modal-title">Product Details</h2>
150
+ <span class="close-modal" onclick="closeProductModal()">&times;</span>
151
+ </div>
152
+ <div class="modal-body">
153
+ <div id="product-modal-content" class="product-details-content">
154
+ <div class="loading">Loading product specifications...</div>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </div>
159
+
160
+ <style>
161
+ .product-details-content {
162
+ max-height: 70vh;
163
+ overflow-y: auto;
164
+ line-height: 1.6;
165
+ }
166
+
167
+ .product-details-content h3 {
168
+ color: #2c3e50;
169
+ margin-top: 20px;
170
+ margin-bottom: 10px;
171
+ }
172
+
173
+ .product-details-content ul {
174
+ margin: 10px 0;
175
+ padding-left: 20px;
176
+ }
177
+
178
+ .product-details-content li {
179
+ margin: 5px 0;
180
+ }
181
+
182
+ .product-details-content strong {
183
+ color: #2980b9;
184
+ }
185
+
186
+ .loading {
187
+ text-align: center;
188
+ padding: 40px;
189
+ color: #7f8c8d;
190
+ }
191
+ </style>
192
+
193
+ <script>
194
+ async function showProductDetails(productName) {
195
+ const modal = document.getElementById('product-details-modal');
196
+ const title = document.getElementById('product-modal-title');
197
+ const content = document.getElementById('product-modal-content');
198
+
199
+ // Show modal with loading state
200
+ modal.style.display = 'flex';
201
+ title.textContent = 'Loading Product Details...';
202
+ content.innerHTML = '<div class="loading">Loading product specifications...</div>';
203
+
204
+ try {
205
+ const response = await fetch(`/api/product/${productName}`);
206
+ const data = await response.json();
207
+
208
+ if (data.success) {
209
+ // Set product title
210
+ const productTitles = {
211
+ 'usb-c-cable': 'USB-C to USB-C Cable',
212
+ '4k-hdmi-cable': '4K HDMI Cable',
213
+ 'charging-hub': 'Multi-Port Charging Hub',
214
+ 'usb-c-hub': 'USB-C Hub Adapter'
215
+ };
216
+
217
+ title.textContent = productTitles[productName] || 'Product Details';
218
+
219
+ // Format and display specifications
220
+ const specs = data.specifications;
221
+ const formattedSpecs = formatProductSpecs(specs);
222
+ content.innerHTML = formattedSpecs;
223
+ } else {
224
+ content.innerHTML = '<div class="error">Failed to load product specifications. Please try again.</div>';
225
+ }
226
+ } catch (error) {
227
+ console.error('Error fetching product details:', error);
228
+ content.innerHTML = '<div class="error">Failed to load product specifications. Please try again.</div>';
229
+ }
230
+ }
231
+
232
+ function formatProductSpecs(specs) {
233
+ // Convert the raw specifications text into formatted HTML
234
+ let formatted = specs
235
+ .replace(/\n\n/g, '</p><p>')
236
+ .replace(/\n/g, '<br>')
237
+ .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
238
+ .replace(/^# (.*?)$/gm, '<h3>$1</h3>')
239
+ .replace(/^## (.*?)$/gm, '<h4>$1</h4>')
240
+ .replace(/^### (.*?)$/gm, '<h5>$1</h5>');
241
+
242
+ return `<div class="specs-content"><p>${formatted}</p></div>`;
243
+ }
244
+
245
+ function closeProductModal() {
246
+ const modal = document.getElementById('product-details-modal');
247
+ modal.style.display = 'none';
248
+ }
249
+
250
+ // Close modal when clicking outside
251
+ document.addEventListener('click', function(e) {
252
+ const modal = document.getElementById('product-details-modal');
253
+ if (e.target === modal) {
254
+ closeProductModal();
255
+ }
256
+ });
257
+ </script>
258
+ {% endblock %}
templates/index.html ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Customer Service - Talk to Agent</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
8
+ </head>
9
+ <body>
10
+ <div class="container">
11
+ <header>
12
+ <h1>Customer Service Chat</h1>
13
+ <div class="status-indicator">
14
+ <div id="status-dot" class="status-dot"></div>
15
+ <span id="status-text">Checking connection...</span>
16
+ </div>
17
+ </header>
18
+
19
+ <div class="main-content">
20
+ <!-- Agent Info Panel -->
21
+ <div class="agent-panel">
22
+ <h3>Customer Service Agent</h3>
23
+ <div class="agent-info">
24
+ <p><strong>AI Agent:</strong> <span id="configured-model">{{ configured_model or 'Loading...' }}</span></p>
25
+ <p><strong>Status:</strong> <span id="agent-status">Connecting...</span></p>
26
+ <p class="agent-description">Your AI-powered customer service assistant is ready to help with product questions, technical support, and general inquiries.</p>
27
+ </div>
28
+ </div>
29
+
30
+ <!-- Chat Interface -->
31
+ <div class="chat-container">
32
+ <div class="chat-header">
33
+ <h3>Chat</h3>
34
+ <button id="clear-chat" class="clear-btn" title="Clear conversation">Clear</button>
35
+ </div>
36
+
37
+ <div id="chat-messages" class="chat-messages">
38
+ <div class="welcome-message">
39
+ <h4>Welcome to Customer Service!</h4>
40
+ <p>Hello! I'm your AI customer service assistant. How can I help you today?</p>
41
+ <ul>
42
+ <li>Ask questions about products and services</li>
43
+ <li>Get technical support and troubleshooting help</li>
44
+ <li>Your conversation history will be preserved</li>
45
+ <li>I can escalate complex issues to human agents</li>
46
+ </ul>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="chat-input-container">
51
+ <div class="input-group">
52
+ <textarea
53
+ id="message-input"
54
+ placeholder="Type your message here..."
55
+ rows="3"
56
+ disabled
57
+ ></textarea>
58
+ <button id="send-btn" disabled>
59
+ <span class="send-icon">➤</span>
60
+ Send
61
+ </button>
62
+ <button type="button" id="end-conversation-button" class="action-button end-conversation" title="End Conversation & Save Summary">
63
+ End Chat
64
+ </button>
65
+ </div>
66
+ <div class="input-info">
67
+ <span id="char-count">0 characters</span>
68
+ <span class="divider">•</span>
69
+ <span>Press Ctrl+Enter to send</span>
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+
75
+ <!-- Loading overlay -->
76
+ <div id="loading-overlay" class="loading-overlay hidden">
77
+ <div class="loading-spinner">
78
+ <div class="spinner"></div>
79
+ <p>Thinking...</p>
80
+ </div>
81
+ </div>
82
+ </div>
83
+
84
+ <script src="{{ url_for('static', filename='script.js') }}"></script>
85
+ </body>
86
+ </html>
templates/products.html ADDED
@@ -0,0 +1,435 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Products - Too Many Cables{% endblock %}
4
+
5
+ {% block content %}
6
+ <!-- Page Header -->
7
+ <section class="page-header">
8
+ <div class="header-container">
9
+ <div class="header-card">
10
+ <h1>Our Products</h1>
11
+ <p>Premium cables and accessories for all your connectivity needs</p>
12
+ </div>
13
+ </div>
14
+ </section>
15
+
16
+ <!-- Products Grid -->
17
+ <section class="products-section">
18
+ <div class="container">
19
+ <div class="products-grid" id="products-grid">
20
+ <!-- USB-C Cables -->
21
+ <div class="product-card" data-category="usb-c" data-price="24.99">
22
+ <div class="product-image">🔌</div>
23
+ <h3>USB-C Premium Cable (100W)</h3>
24
+ <p class="product-description">100W fast charging, 10Gbps data transfer, 6ft length with braided nylon protection</p>
25
+ <div class="product-specs">
26
+ <span class="spec">100W Power</span>
27
+ <span class="spec">10Gbps Speed</span>
28
+ <span class="spec">6ft Length</span>
29
+ </div>
30
+ <div class="product-price">$24.99</div>
31
+ <div class="product-rating">⭐⭐⭐⭐⭐ (1,247 reviews)</div>
32
+ <button class="btn btn-primary" onclick="showProductDetails('usb-c-cable')">More Details</button>
33
+ </div>
34
+
35
+ <div class="product-card" data-category="usb-c" data-price="19.99">
36
+ <div class="product-image">🔌</div>
37
+ <h3>USB-C Standard Cable (60W)</h3>
38
+ <p class="product-description">60W fast charging, 5Gbps data transfer, 3ft compact design with PVC jacket</p>
39
+ <div class="product-specs">
40
+ <span class="spec">60W Power</span>
41
+ <span class="spec">5Gbps Speed</span>
42
+ <span class="spec">3ft Length</span>
43
+ </div>
44
+ <div class="product-price">$19.99</div>
45
+ <div class="product-rating">⭐⭐⭐⭐⭐ (892 reviews)</div>
46
+ <button class="btn btn-primary" onclick="showProductDetails('usb-c-standard')">More Details</button>
47
+ </div>
48
+
49
+ <div class="product-card" data-category="usb-c" data-price="16.99">
50
+ <div class="product-image">🔌</div>
51
+ <h3>USB-A to USB-C Cable</h3>
52
+ <p class="product-description">Universal compatibility, 18W fast charging, 6ft braided design</p>
53
+ <div class="product-specs">
54
+ <span class="spec">18W Charging</span>
55
+ <span class="spec">5Gbps Speed</span>
56
+ <span class="spec">6ft Length</span>
57
+ </div>
58
+ <div class="product-price">$16.99</div>
59
+ <div class="product-rating">⭐⭐⭐⭐⭐ (734 reviews)</div>
60
+ <button class="btn btn-primary" onclick="showProductDetails('usb-c-to-usb-a')">More Details</button>
61
+ </div>
62
+
63
+ <!-- HDMI Cables -->
64
+ <div class="product-card" data-category="hdmi" data-price="34.99">
65
+ <div class="product-image">📺</div>
66
+ <h3>8K HDMI Cable (Ultra High Speed)</h3>
67
+ <p class="product-description">8K@60Hz, 4K@120Hz, HDR10+, Dolby Vision, premium 10ft cable with gold-plated connectors</p>
68
+ <div class="product-specs">
69
+ <span class="spec">8K@60Hz</span>
70
+ <span class="spec">48 Gbps</span>
71
+ <span class="spec">10ft Length</span>
72
+ </div>
73
+ <div class="product-price">$34.99</div>
74
+ <div class="product-rating">⭐⭐⭐⭐⭐ (856 reviews)</div>
75
+ <button class="btn btn-primary" onclick="showProductDetails('4k-hdmi-cable')">More Details</button>
76
+ </div>
77
+
78
+ <div class="product-card" data-category="hdmi" data-price="24.99">
79
+ <div class="product-image">📺</div>
80
+ <h3>4K HDMI Cable (High Speed)</h3>
81
+ <p class="product-description">4K@60Hz, 1440p@144Hz, HDR10+, ARC audio, 6ft cable with durable PVC jacket</p>
82
+ <div class="product-specs">
83
+ <span class="spec">4K@60Hz</span>
84
+ <span class="spec">18 Gbps</span>
85
+ <span class="spec">6ft Length</span>
86
+ </div>
87
+ <div class="product-price">$24.99</div>
88
+ <div class="product-rating">⭐⭐⭐⭐⭐ (634 reviews)</div>
89
+ <button class="btn btn-primary" onclick="showProductDetails('hdmi-standard')">More Details</button>
90
+ </div>
91
+
92
+ <div class="product-card" data-category="hdmi" data-price="18.99">
93
+ <div class="product-image">📺</div>
94
+ <h3>HDMI to USB-C Cable</h3>
95
+ <p class="product-description">Direct connection from laptop to monitor, 4K@60Hz, 6ft cable</p>
96
+ <div class="product-specs">
97
+ <span class="spec">4K@60Hz</span>
98
+ <span class="spec">Plug & Play</span>
99
+ <span class="spec">6ft Length</span>
100
+ </div>
101
+ <div class="product-price">$18.99</div>
102
+ <div class="product-rating">⭐⭐⭐⭐⭐ (445 reviews)</div>
103
+ <button class="btn btn-primary" onclick="showProductDetails('hdmi-usb-c-cable')">More Details</button>
104
+ </div>
105
+
106
+ <div class="product-card" data-category="hdmi" data-price="14.99">
107
+ <div class="product-image">📺</div>
108
+ <h3>Mini HDMI to HDMI Cable</h3>
109
+ <p class="product-description">Connect tablets and cameras to displays, 4K@30Hz, 3ft flexible design</p>
110
+ <div class="product-specs">
111
+ <span class="spec">4K@30Hz</span>
112
+ <span class="spec">Mini HDMI</span>
113
+ <span class="spec">3ft Length</span>
114
+ </div>
115
+ <div class="product-price">$14.99</div>
116
+ <div class="product-rating">⭐⭐⭐⭐⭐ (312 reviews)</div>
117
+ <button class="btn btn-primary" onclick="showProductDetails('mini-hdmi-cable')">More Details</button>
118
+ </div>
119
+
120
+ <div class="product-card" data-category="hdmi" data-price="14.99">
121
+ <div class="product-image">📺</div>
122
+ <h3>Micro HDMI to HDMI Cable</h3>
123
+ <p class="product-description">Connect action cameras and devices to displays, 4K@30Hz, 3ft ultra-flexible</p>
124
+ <div class="product-specs">
125
+ <span class="spec">4K@30Hz</span>
126
+ <span class="spec">Micro HDMI</span>
127
+ <span class="spec">3ft Length</span>
128
+ </div>
129
+ <div class="product-price">$14.99</div>
130
+ <div class="product-rating">⭐⭐⭐⭐⭐ (284 reviews)</div>
131
+ <button class="btn btn-primary" onclick="showProductDetails('micro-hdmi-cable')">More Details</button>
132
+ </div>
133
+
134
+ <!-- Lightning Cables -->
135
+ <div class="product-card" data-category="lightning" data-price="19.99">
136
+ <div class="product-image">⚡</div>
137
+ <h3>Lightning to USB-A Cable (MFi)</h3>
138
+ <p class="product-description">Apple MFi certified, 2.4A fast charging, 6ft durable cable for iPhone and iPad</p>
139
+ <div class="product-specs">
140
+ <span class="spec">MFi Certified</span>
141
+ <span class="spec">2.4A Charging</span>
142
+ <span class="spec">6ft Length</span>
143
+ </div>
144
+ <div class="product-price">$19.99</div>
145
+ <div class="product-rating">⭐⭐⭐⭐⭐ (1,542 reviews)</div>
146
+ <button class="btn btn-primary" onclick="showProductDetails('lightning-cable')">More Details</button>
147
+ </div>
148
+
149
+ <!-- Charging Cables -->
150
+ <div class="product-card" data-category="charging" data-price="49.99">
151
+ <div class="product-image">🔋</div>
152
+ <h3>Multi-Port Charging Hub</h3>
153
+ <p class="product-description">6 ports, 100W total power, USB-C PD, smart charging technology</p>
154
+ <div class="product-specs">
155
+ <span class="spec">100W Total</span>
156
+ <span class="spec">6 Ports</span>
157
+ <span class="spec">Smart Charging</span>
158
+ </div>
159
+ <div class="product-price">$49.99</div>
160
+ <div class="product-rating">⭐⭐⭐⭐⭐ (692 reviews)</div>
161
+ <button class="btn btn-primary" onclick="showProductDetails('charging-hub')">More Details</button>
162
+ </div>
163
+
164
+ <div class="product-card" data-category="charging" data-price="29.99">
165
+ <div class="product-image">⚡</div>
166
+ <h3>Wireless Charging Pad</h3>
167
+ <p class="product-description">15W fast wireless charging, Qi-certified, LED indicator, non-slip design</p>
168
+ <div class="product-specs">
169
+ <span class="spec">15W Fast</span>
170
+ <span class="spec">Qi Certified</span>
171
+ <span class="spec">LED Status</span>
172
+ </div>
173
+ <div class="product-price">$29.99</div>
174
+ <div class="product-rating">⭐⭐⭐⭐⭐ (445 reviews)</div>
175
+ <button class="btn btn-primary" onclick="showProductDetails('wireless-charging')">More Details</button>
176
+ </div>
177
+
178
+ <!-- Adapters & Hubs -->
179
+ <div class="product-card" data-category="adapters" data-price="34.99">
180
+ <div class="product-image">🔗</div>
181
+ <h3>USB-C Hub Adapter</h3>
182
+ <p class="product-description">7-in-1 hub with HDMI, USB-A, SD card, Ethernet, compact aluminum design</p>
183
+ <div class="product-specs">
184
+ <span class="spec">7-in-1 Hub</span>
185
+ <span class="spec">4K HDMI</span>
186
+ <span class="spec">Gigabit Ethernet</span>
187
+ </div>
188
+ <div class="product-price">$34.99</div>
189
+ <div class="product-rating">⭐⭐⭐⭐⭐ (1,104 reviews)</div>
190
+ <button class="btn btn-primary" onclick="showProductDetails('usb-c-hub')">More Details</button>
191
+ </div>
192
+
193
+ <div class="product-card" data-category="adapters" data-price="12.99">
194
+ <div class="product-image">🔄</div>
195
+ <h3>USB-C to HDMI Adapter</h3>
196
+ <p class="product-description">4K@30Hz video output, plug and play, ultra-compact design</p>
197
+ <div class="product-specs">
198
+ <span class="spec">4K@30Hz</span>
199
+ <span class="spec">Plug & Play</span>
200
+ <span class="spec">Compact</span>
201
+ </div>
202
+ <div class="product-price">$12.99</div>
203
+ <div class="product-rating">⭐⭐⭐⭐⭐ (789 reviews)</div>
204
+ <button class="btn btn-primary" onclick="showProductDetails('usb-c-hdmi-adapter')">More Details</button>
205
+ </div>
206
+
207
+ <!-- Audio Cables -->
208
+ <div class="product-card" data-category="audio" data-price="16.99">
209
+ <div class="product-image">🎧</div>
210
+ <h3>3.5mm Audio Cable</h3>
211
+ <p class="product-description">Premium gold-plated connectors, tangle-free design, 6ft length</p>
212
+ <div class="product-specs">
213
+ <span class="spec">Gold Plated</span>
214
+ <span class="spec">Tangle Free</span>
215
+ <span class="spec">6ft Length</span>
216
+ </div>
217
+ <div class="product-price">$16.99</div>
218
+ <div class="product-rating">⭐⭐⭐⭐⭐ (567 reviews)</div>
219
+ <button class="btn btn-primary" onclick="showProductDetails('audio-cable')">More Details</button>
220
+ </div>
221
+
222
+ <div class="product-card" data-category="audio" data-price="22.99">
223
+ <div class="product-image">🎵</div>
224
+ <h3>USB-C to 3.5mm Adapter</h3>
225
+ <p class="product-description">High-resolution audio, 32-bit DAC, compact aluminum housing</p>
226
+ <div class="product-specs">
227
+ <span class="spec">Hi-Res Audio</span>
228
+ <span class="spec">32-bit DAC</span>
229
+ <span class="spec">Aluminum</span>
230
+ </div>
231
+ <div class="product-price">$22.99</div>
232
+ <div class="product-rating">⭐⭐⭐⭐⭐ (423 reviews)</div>
233
+ <button class="btn btn-primary" onclick="showProductDetails('usb-c-audio-adapter')">More Details</button>
234
+ </div>
235
+ </div>
236
+ </div>
237
+ </section>
238
+
239
+ <!-- Product Support CTA -->
240
+ <section class="product-support-cta">
241
+ <div class="container">
242
+ <div class="cta-content">
243
+ <h2>Need Help Choosing?</h2>
244
+ <p>Our AI assistant can help you find the perfect cable for your specific needs.</p>
245
+ <a href="#" class="btn btn-primary btn-large chat-trigger-btn">Get Product Recommendations 💬</a>
246
+ </div>
247
+ </div>
248
+ </section>
249
+
250
+ <!-- Product Details Modal -->
251
+ <div id="product-details-modal" class="modal" style="display: none;">
252
+ <div class="modal-content">
253
+ <div class="modal-header">
254
+ <h2 id="product-modal-title">Product Details</h2>
255
+ <span class="close-modal" onclick="closeProductModal()">&times;</span>
256
+ </div>
257
+ <div class="modal-body">
258
+ <div id="product-modal-content" class="product-details-content">
259
+ <div class="loading">Loading product specifications...</div>
260
+ </div>
261
+ </div>
262
+ </div>
263
+ </div>
264
+
265
+ <style>
266
+ .product-details-content {
267
+ max-height: 70vh;
268
+ overflow-y: auto;
269
+ line-height: 1.6;
270
+ }
271
+
272
+ .product-details-content h3 {
273
+ color: #2c3e50;
274
+ margin-top: 20px;
275
+ margin-bottom: 10px;
276
+ }
277
+
278
+ .product-details-content h4 {
279
+ color: #34495e;
280
+ margin-top: 15px;
281
+ margin-bottom: 8px;
282
+ }
283
+
284
+ .product-details-content h5 {
285
+ color: #5d6d7e;
286
+ margin-top: 12px;
287
+ margin-bottom: 6px;
288
+ }
289
+
290
+ .product-details-content ul {
291
+ margin: 10px 0;
292
+ padding-left: 20px;
293
+ }
294
+
295
+ .product-details-content li {
296
+ margin: 5px 0;
297
+ }
298
+
299
+ .product-details-content strong {
300
+ color: #2980b9;
301
+ }
302
+
303
+ .loading {
304
+ text-align: center;
305
+ padding: 40px;
306
+ color: #7f8c8d;
307
+ }
308
+
309
+ .error {
310
+ text-align: center;
311
+ padding: 40px;
312
+ color: #e74c3c;
313
+ }
314
+
315
+ .specs-content {
316
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
317
+ }
318
+ </style>
319
+ {% endblock %}
320
+
321
+ {% block extra_scripts %}
322
+ <script>
323
+ // Product filtering functionality
324
+ document.addEventListener('DOMContentLoaded', function() {
325
+ const categoryFilter = document.getElementById('category-filter');
326
+ const priceFilter = document.getElementById('price-filter');
327
+ const productsGrid = document.getElementById('products-grid');
328
+ const products = Array.from(productsGrid.querySelectorAll('.product-card'));
329
+
330
+ function filterProducts() {
331
+ const selectedCategory = categoryFilter.value;
332
+ const selectedPriceRange = priceFilter.value;
333
+
334
+ products.forEach(product => {
335
+ const category = product.dataset.category;
336
+ const price = parseFloat(product.dataset.price);
337
+
338
+ let showProduct = true;
339
+
340
+ // Category filter
341
+ if (selectedCategory && category !== selectedCategory) {
342
+ showProduct = false;
343
+ }
344
+
345
+ // Price filter
346
+ if (selectedPriceRange) {
347
+ const [min, max] = selectedPriceRange.split('-').map(p => p === '+' ? Infinity : parseFloat(p));
348
+ if (selectedPriceRange.includes('+')) {
349
+ if (price < min) showProduct = false;
350
+ } else {
351
+ if (price < min || price > max) showProduct = false;
352
+ }
353
+ }
354
+
355
+ product.style.display = showProduct ? 'block' : 'none';
356
+ });
357
+ }
358
+
359
+ // Event listeners
360
+ categoryFilter.addEventListener('change', filterProducts);
361
+ priceFilter.addEventListener('change', filterProducts);
362
+ });
363
+
364
+ // Product details functionality
365
+ async function showProductDetails(productName) {
366
+ const modal = document.getElementById('product-details-modal');
367
+ const title = document.getElementById('product-modal-title');
368
+ const content = document.getElementById('product-modal-content');
369
+
370
+ // Show modal with loading state
371
+ modal.style.display = 'flex';
372
+ title.textContent = 'Loading Product Details...';
373
+ content.innerHTML = '<div class="loading">Loading product specifications...</div>';
374
+
375
+ try {
376
+ const response = await fetch(`/api/product/${productName}`);
377
+ const data = await response.json();
378
+
379
+ if (data.success) {
380
+ // Set product title
381
+ const productTitles = {
382
+ 'usb-c-cable': 'USB-C to USB-C Cable',
383
+ 'usb-c-to-usb-a': 'USB-C to USB-A Cable',
384
+ '4k-hdmi-cable': '4K HDMI Cable',
385
+ 'hdmi-usb-c-cable': 'HDMI to USB-C Cable',
386
+ 'charging-hub': 'Multi-Port Charging Hub',
387
+ 'wireless-charging': 'Wireless Charging Pad',
388
+ 'usb-c-hub': 'USB-C Hub Adapter',
389
+ 'usb-c-hdmi-adapter': 'USB-C to HDMI Adapter',
390
+ 'audio-cable': '3.5mm Audio Cable',
391
+ 'usb-c-audio-adapter': 'USB-C to 3.5mm Adapter'
392
+ };
393
+
394
+ title.textContent = productTitles[productName] || 'Product Details';
395
+
396
+ // Format and display specifications
397
+ const specs = data.specifications;
398
+ const formattedSpecs = formatProductSpecs(specs);
399
+ content.innerHTML = formattedSpecs;
400
+ } else {
401
+ content.innerHTML = '<div class="error">Failed to load product specifications. Please try again.</div>';
402
+ }
403
+ } catch (error) {
404
+ console.error('Error fetching product details:', error);
405
+ content.innerHTML = '<div class="error">Failed to load product specifications. Please try again.</div>';
406
+ }
407
+ }
408
+
409
+ function formatProductSpecs(specs) {
410
+ // Convert the raw specifications text into formatted HTML
411
+ let formatted = specs
412
+ .replace(/\n\n/g, '</p><p>')
413
+ .replace(/\n/g, '<br>')
414
+ .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
415
+ .replace(/^# (.*?)$/gm, '<h3>$1</h3>')
416
+ .replace(/^## (.*?)$/gm, '<h4>$1</h4>')
417
+ .replace(/^### (.*?)$/gm, '<h5>$1</h5>');
418
+
419
+ return `<div class="specs-content"><p>${formatted}</p></div>`;
420
+ }
421
+
422
+ function closeProductModal() {
423
+ const modal = document.getElementById('product-details-modal');
424
+ modal.style.display = 'none';
425
+ }
426
+
427
+ // Close modal when clicking outside
428
+ document.addEventListener('click', function(e) {
429
+ const modal = document.getElementById('product-details-modal');
430
+ if (e.target === modal) {
431
+ closeProductModal();
432
+ }
433
+ });
434
+ </script>
435
+ {% endblock %}
templates/support.html ADDED
File without changes
templates/tickets.html ADDED
@@ -0,0 +1,940 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}My Support Tickets - Too Many Cables{% endblock %}
4
+
5
+ {% block description %}Manage your support tickets and track the status of your requests with Too Many Cables customer service.{% endblock %}
6
+
7
+ {% block content %}
8
+ <div class="tickets-container">
9
+ <div class="page-header">
10
+ <h1 class="page-title">My Support Tickets</h1>
11
+ <p class="page-subtitle">Track and manage your support requests</p>
12
+ </div>
13
+
14
+ <!-- User must be logged in to view tickets -->
15
+ <div id="auth-required" class="auth-message" style="display: none;">
16
+ <div class="glass-card">
17
+ <h3>Login Required</h3>
18
+ <p>Please log in to view and manage your support tickets.</p>
19
+ <button class="btn btn-primary" onclick="showLoginModal()">Login</button>
20
+ </div>
21
+ </div>
22
+
23
+ <!-- Main tickets interface -->
24
+ <div id="tickets-main" style="display: none;">
25
+ <!-- Create New Ticket Section -->
26
+ <div class="glass-card ticket-creation">
27
+ <h3>Create New Ticket</h3>
28
+ <form id="create-ticket-form">
29
+ <div class="form-group">
30
+ <label for="ticket-subject">Subject</label>
31
+ <input type="text" id="ticket-subject" name="subject" required
32
+ placeholder="Brief description of your issue">
33
+ </div>
34
+
35
+ <div class="form-group">
36
+ <label for="ticket-description">Description</label>
37
+ <textarea id="ticket-description" name="description" required
38
+ placeholder="Please provide detailed information about your issue"
39
+ rows="4"></textarea>
40
+ </div>
41
+
42
+ <div class="form-row">
43
+ <div class="form-group">
44
+ <label for="ticket-priority">Priority</label>
45
+ <select id="ticket-priority" name="priority">
46
+ <option value="low">Low</option>
47
+ <option value="medium" selected>Medium</option>
48
+ <option value="high">High</option>
49
+ <option value="urgent">Urgent</option>
50
+ </select>
51
+ </div>
52
+
53
+ <div class="form-group">
54
+ <label for="ticket-category">Category</label>
55
+ <select id="ticket-category" name="category">
56
+ <option value="">Auto-detect</option>
57
+ </select>
58
+ </div>
59
+ </div>
60
+
61
+ <button type="submit" class="btn btn-primary">Create Ticket</button>
62
+ </form>
63
+ </div>
64
+
65
+ <!-- Tickets List -->
66
+ <div class="glass-card tickets-list">
67
+ <div class="tickets-header">
68
+ <h3>Your Tickets</h3>
69
+ <div class="tickets-filters">
70
+ <select id="status-filter">
71
+ <option value="">All Status</option>
72
+ <option value="open">Open</option>
73
+ <option value="in_progress">In Progress</option>
74
+ <option value="resolved">Resolved</option>
75
+ <option value="closed">Closed</option>
76
+ </select>
77
+ </div>
78
+ </div>
79
+
80
+ <div id="tickets-loading" class="loading-state">
81
+ <div class="spinner"></div>
82
+ <p>Loading your tickets...</p>
83
+ </div>
84
+
85
+ <div id="tickets-empty" class="empty-state" style="display: none;">
86
+ <h4>No tickets yet</h4>
87
+ <p>When you create support tickets, they'll appear here.</p>
88
+ </div>
89
+
90
+ <div id="tickets-container"></div>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ <!-- Ticket Detail Modal -->
96
+ <div id="ticket-modal" class="modal" style="display: none;">
97
+ <div class="modal-content glass-card">
98
+ <div class="modal-header">
99
+ <h3 id="ticket-modal-title">Ticket Details</h3>
100
+ <button class="modal-close" onclick="closeTicketModal()">&times;</button>
101
+ </div>
102
+
103
+ <div class="modal-body">
104
+ <div id="ticket-details"></div>
105
+
106
+ <!-- SLA and Escalation Status -->
107
+ <div id="sla-status" class="sla-section" style="display: none;"></div>
108
+
109
+ <!-- Escalation Actions -->
110
+ <div id="escalation-actions" class="escalation-section" style="display: none;">
111
+ <h4>Escalation</h4>
112
+ <button class="btn btn-warning" onclick="escalateTicket()">Request Escalation</button>
113
+ <p style="font-size: 0.9rem; color: rgba(0,0,0,0.7); margin-top: 0.5rem;">
114
+ Request priority escalation if your issue needs immediate attention.
115
+ </p>
116
+ </div>
117
+
118
+ <!-- Add Update Form -->
119
+ <div class="ticket-update-form">
120
+ <h4>Add Update</h4>
121
+ <form id="update-ticket-form">
122
+ <input type="hidden" id="update-ticket-id">
123
+ <div class="form-group">
124
+ <textarea id="update-message" placeholder="Add a comment or update..."
125
+ rows="3" required></textarea>
126
+ </div>
127
+ <button type="submit" class="btn btn-primary">Add Update</button>
128
+ </form>
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </div>
133
+
134
+ <style>
135
+ .tickets-container {
136
+ max-width: 1200px;
137
+ margin: 0 auto;
138
+ padding: 2rem;
139
+ }
140
+
141
+ .page-header {
142
+ text-align: center;
143
+ margin-bottom: 3rem;
144
+ }
145
+
146
+ .page-title {
147
+ font-size: 2.5rem;
148
+ font-weight: 700;
149
+ color: white;
150
+ text-shadow: 0 2px 10px rgba(0,0,0,0.3);
151
+ margin-bottom: 0.5rem;
152
+ }
153
+
154
+ .page-subtitle {
155
+ font-size: 1.1rem;
156
+ color: rgba(255,255,255,0.9);
157
+ font-weight: 300;
158
+ }
159
+
160
+ .glass-card {
161
+ background: rgba(255, 255, 255, 0.15);
162
+ backdrop-filter: blur(25px);
163
+ -webkit-backdrop-filter: blur(25px);
164
+ border-radius: 20px;
165
+ border: 1px solid rgba(255, 255, 255, 0.2);
166
+ padding: 2rem;
167
+ margin-bottom: 2rem;
168
+ box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
169
+ }
170
+
171
+ .ticket-creation h3,
172
+ .tickets-list h3 {
173
+ color: white;
174
+ margin-bottom: 1.5rem;
175
+ font-weight: 600;
176
+ }
177
+
178
+ .form-group {
179
+ margin-bottom: 1.5rem;
180
+ }
181
+
182
+ .form-row {
183
+ display: grid;
184
+ grid-template-columns: 1fr 1fr;
185
+ gap: 1rem;
186
+ }
187
+
188
+ .form-group label {
189
+ display: block;
190
+ color: rgba(255,255,255,0.9);
191
+ margin-bottom: 0.5rem;
192
+ font-weight: 500;
193
+ }
194
+
195
+ .form-group input,
196
+ .form-group textarea,
197
+ .form-group select {
198
+ width: 100%;
199
+ padding: 0.75rem 1rem;
200
+ border: 1px solid rgba(255,255,255,0.3);
201
+ border-radius: 10px;
202
+ background: rgba(255,255,255,0.1);
203
+ color: white;
204
+ font-size: 1rem;
205
+ transition: all 0.3s ease;
206
+ }
207
+
208
+ .form-group input:focus,
209
+ .form-group textarea:focus,
210
+ .form-group select:focus {
211
+ outline: none;
212
+ border-color: rgba(255,255,255,0.6);
213
+ background: rgba(255,255,255,0.2);
214
+ box-shadow: 0 0 0 3px rgba(255,255,255,0.1);
215
+ }
216
+
217
+ .form-group input::placeholder,
218
+ .form-group textarea::placeholder {
219
+ color: rgba(255,255,255,0.6);
220
+ }
221
+
222
+ .btn {
223
+ padding: 0.75rem 1.5rem;
224
+ border: none;
225
+ border-radius: 10px;
226
+ font-weight: 600;
227
+ text-decoration: none;
228
+ display: inline-block;
229
+ transition: all 0.3s ease;
230
+ cursor: pointer;
231
+ font-size: 1rem;
232
+ }
233
+
234
+ .btn-primary {
235
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
236
+ color: white;
237
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
238
+ }
239
+
240
+ .btn-primary:hover {
241
+ transform: translateY(-2px);
242
+ box-shadow: 0 8px 25px rgba(102, 126, 234, 0.6);
243
+ }
244
+
245
+ .tickets-header {
246
+ display: flex;
247
+ justify-content: space-between;
248
+ align-items: center;
249
+ margin-bottom: 1.5rem;
250
+ }
251
+
252
+ .tickets-filters select {
253
+ padding: 0.5rem 1rem;
254
+ border: 1px solid rgba(255,255,255,0.3);
255
+ border-radius: 8px;
256
+ background: rgba(255,255,255,0.1);
257
+ color: white;
258
+ }
259
+
260
+ .ticket-item {
261
+ background: rgba(255,255,255,0.1);
262
+ border-radius: 10px;
263
+ padding: 1.5rem;
264
+ margin-bottom: 1rem;
265
+ border: 1px solid rgba(255,255,255,0.2);
266
+ cursor: pointer;
267
+ transition: all 0.3s ease;
268
+ }
269
+
270
+ .ticket-item:hover {
271
+ background: rgba(255,255,255,0.2);
272
+ transform: translateY(-2px);
273
+ }
274
+
275
+ .ticket-header {
276
+ display: flex;
277
+ justify-content: space-between;
278
+ align-items: start;
279
+ margin-bottom: 0.5rem;
280
+ }
281
+
282
+ .ticket-number {
283
+ font-weight: 600;
284
+ color: white;
285
+ font-size: 1.1rem;
286
+ }
287
+
288
+ .ticket-status {
289
+ padding: 0.25rem 0.75rem;
290
+ border-radius: 20px;
291
+ font-size: 0.85rem;
292
+ font-weight: 500;
293
+ text-transform: uppercase;
294
+ }
295
+
296
+ .status-open { background: #f39c12; color: white; }
297
+ .status-in_progress { background: #3498db; color: white; }
298
+ .status-resolved { background: #27ae60; color: white; }
299
+ .status-closed { background: #95a5a6; color: white; }
300
+
301
+ .ticket-subject {
302
+ color: white;
303
+ font-size: 1.1rem;
304
+ margin-bottom: 0.5rem;
305
+ font-weight: 500;
306
+ }
307
+
308
+ .ticket-meta {
309
+ display: flex;
310
+ justify-content: space-between;
311
+ align-items: center;
312
+ color: rgba(255,255,255,0.7);
313
+ font-size: 0.9rem;
314
+ }
315
+
316
+ .ticket-category {
317
+ background: rgba(255,255,255,0.2);
318
+ padding: 0.25rem 0.5rem;
319
+ border-radius: 15px;
320
+ font-size: 0.8rem;
321
+ }
322
+
323
+ .loading-state,
324
+ .empty-state {
325
+ text-align: center;
326
+ padding: 2rem;
327
+ color: rgba(255,255,255,0.8);
328
+ }
329
+
330
+ .spinner {
331
+ border: 3px solid rgba(255,255,255,0.3);
332
+ border-top: 3px solid white;
333
+ border-radius: 50%;
334
+ width: 40px;
335
+ height: 40px;
336
+ animation: spin 1s linear infinite;
337
+ margin: 0 auto 1rem;
338
+ }
339
+
340
+ @keyframes spin {
341
+ 0% { transform: rotate(0deg); }
342
+ 100% { transform: rotate(360deg); }
343
+ }
344
+
345
+ .modal {
346
+ position: fixed;
347
+ top: 0;
348
+ left: 0;
349
+ right: 0;
350
+ bottom: 0;
351
+ background: rgba(0,0,0,0.8);
352
+ display: flex;
353
+ justify-content: center;
354
+ align-items: center;
355
+ z-index: 2000;
356
+ }
357
+
358
+ .modal-content {
359
+ max-width: 600px;
360
+ width: 90%;
361
+ max-height: 80vh;
362
+ overflow-y: auto;
363
+ margin: 2rem;
364
+ }
365
+
366
+ .modal-header {
367
+ display: flex;
368
+ justify-content: space-between;
369
+ align-items: center;
370
+ margin-bottom: 1.5rem;
371
+ }
372
+
373
+ .modal-close {
374
+ background: none;
375
+ border: none;
376
+ color: #1a202c; /* dark close button for contrast on light modal */
377
+ font-size: 2rem;
378
+ cursor: pointer;
379
+ opacity: 0.8;
380
+ transition: opacity 0.3s ease;
381
+ }
382
+
383
+ .modal-close:hover {
384
+ opacity: 1;
385
+ }
386
+
387
+ /* Ensure modal header and title are dark for readability */
388
+ .modal-header h3, .modal-content h3 {
389
+ color: #1a202c !important;
390
+ }
391
+
392
+ .auth-message {
393
+ text-align: center;
394
+ padding: 3rem 2rem;
395
+ }
396
+
397
+ .auth-message h3 {
398
+ color: white;
399
+ margin-bottom: 1rem;
400
+ }
401
+
402
+ .auth-message p {
403
+ color: rgba(255,255,255,0.8);
404
+ margin-bottom: 2rem;
405
+ }
406
+
407
+ .ticket-update-form {
408
+ margin-top: 2rem;
409
+ padding-top: 2rem;
410
+ border-top: 1px solid rgba(255,255,255,0.2);
411
+ }
412
+
413
+ .ticket-update-form h4 {
414
+ color: white;
415
+ margin-bottom: 1rem;
416
+ }
417
+
418
+ .escalation-badge {
419
+ background: #e74c3c;
420
+ color: white;
421
+ padding: 0.25rem 0.5rem;
422
+ border-radius: 12px;
423
+ font-size: 0.75rem;
424
+ font-weight: 600;
425
+ margin-left: 0.5rem;
426
+ }
427
+
428
+ /* Ensure ticket modal content is readable: light card with dark text */
429
+ .modal-content {
430
+ background: rgba(255,255,255,0.98) !important;
431
+ color: #1a202c !important;
432
+ border-radius: 12px;
433
+ padding: 1.5rem;
434
+ box-shadow: 0 10px 30px rgba(0,0,0,0.3);
435
+ }
436
+
437
+ /* Strong override: force dark text for modal and all children to avoid inheritance issues */
438
+ .modal-content.glass-card,
439
+ .modal-content.glass-card * {
440
+ color: #1a202c !important;
441
+ }
442
+
443
+ /* Ensure headings and paragraphs within modal are readable */
444
+ .modal-content h1,
445
+ .modal-content h2,
446
+ .modal-content h3,
447
+ .modal-content h4,
448
+ .modal-content p,
449
+ .modal-content label,
450
+ .modal-content span,
451
+ .modal-content div {
452
+ color: #1a202c !important;
453
+ }
454
+
455
+ .sla-section {
456
+ background: rgba(255,255,255,0.1);
457
+ border-radius: 10px;
458
+ padding: 1.5rem;
459
+ margin: 1.5rem 0;
460
+ border-left: 4px solid #3498db;
461
+ }
462
+
463
+ .sla-section h4 {
464
+ color: white;
465
+ margin-bottom: 1rem;
466
+ }
467
+
468
+ .sla-metric {
469
+ display: flex;
470
+ justify-content: space-between;
471
+ align-items: center;
472
+ margin-bottom: 0.5rem;
473
+ color: rgba(255,255,255,0.9);
474
+ }
475
+
476
+ .sla-status {
477
+ padding: 0.25rem 0.75rem;
478
+ border-radius: 15px;
479
+ font-size: 0.85rem;
480
+ font-weight: 500;
481
+ }
482
+
483
+ .sla-met { background: #27ae60; color: white; }
484
+ .sla-warning { background: #f39c12; color: white; }
485
+ .sla-breach { background: #e74c3c; color: white; }
486
+
487
+ .escalation-section {
488
+ background: rgba(255,255,255,0.1);
489
+ border-radius: 10px;
490
+ padding: 1.5rem;
491
+ margin: 1.5rem 0;
492
+ border-left: 4px solid #e74c3c;
493
+ }
494
+
495
+ .escalation-section h4 {
496
+ color: white;
497
+ margin-bottom: 1rem;
498
+ }
499
+
500
+ .btn-warning {
501
+ background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%);
502
+ color: white;
503
+ box-shadow: 0 4px 15px rgba(243, 156, 18, 0.4);
504
+ }
505
+
506
+ .btn-warning:hover {
507
+ transform: translateY(-2px);
508
+ box-shadow: 0 8px 25px rgba(243, 156, 18, 0.6);
509
+ }
510
+
511
+ @media (max-width: 768px) {
512
+ .form-row {
513
+ grid-template-columns: 1fr;
514
+ }
515
+
516
+ .tickets-header {
517
+ flex-direction: column;
518
+ gap: 1rem;
519
+ align-items: stretch;
520
+ }
521
+
522
+ .ticket-header {
523
+ flex-direction: column;
524
+ gap: 0.5rem;
525
+ }
526
+
527
+ .ticket-meta {
528
+ flex-direction: column;
529
+ gap: 0.5rem;
530
+ align-items: start;
531
+ }
532
+ }
533
+ </style>
534
+
535
+ <script>
536
+ // Ticket management functionality
537
+ let currentUser = null;
538
+ let tickets = [];
539
+ let categories = [];
540
+
541
+ // Initialize page
542
+ document.addEventListener('DOMContentLoaded', function() {
543
+ checkAuthentication();
544
+ loadCategories();
545
+ });
546
+
547
+ function checkAuthentication() {
548
+ fetch('/api/user')
549
+ .then(response => response.json())
550
+ .then(data => {
551
+ if (data.success && data.user) {
552
+ currentUser = data.user;
553
+ document.getElementById('auth-required').style.display = 'none';
554
+ document.getElementById('tickets-main').style.display = 'block';
555
+ loadTickets();
556
+
557
+ // Show tickets link in navigation
558
+ const ticketsLink = document.getElementById('tickets-link');
559
+ if (ticketsLink) {
560
+ ticketsLink.style.display = 'inline-block';
561
+ }
562
+ } else {
563
+ document.getElementById('auth-required').style.display = 'block';
564
+ document.getElementById('tickets-main').style.display = 'none';
565
+ }
566
+ })
567
+ .catch(error => {
568
+ console.error('Auth check failed:', error);
569
+ document.getElementById('auth-required').style.display = 'block';
570
+ });
571
+ }
572
+
573
+ function loadCategories() {
574
+ fetch('/api/tickets/categories')
575
+ .then(response => response.json())
576
+ .then(data => {
577
+ if (data.success) {
578
+ categories = data.categories;
579
+ const categorySelect = document.getElementById('ticket-category');
580
+ categorySelect.innerHTML = '<option value="">Auto-detect</option>';
581
+
582
+ categories.forEach(category => {
583
+ const option = document.createElement('option');
584
+ option.value = category.name;
585
+ option.textContent = category.name;
586
+ categorySelect.appendChild(option);
587
+ });
588
+ }
589
+ })
590
+ .catch(error => console.error('Failed to load categories:', error));
591
+ }
592
+
593
+ function loadTickets() {
594
+ document.getElementById('tickets-loading').style.display = 'block';
595
+ document.getElementById('tickets-empty').style.display = 'none';
596
+ document.getElementById('tickets-container').innerHTML = '';
597
+
598
+ fetch('/api/tickets/user')
599
+ .then(response => response.json())
600
+ .then(data => {
601
+ document.getElementById('tickets-loading').style.display = 'none';
602
+
603
+ if (data.success) {
604
+ tickets = data.tickets;
605
+ if (tickets.length === 0) {
606
+ document.getElementById('tickets-empty').style.display = 'block';
607
+ } else {
608
+ displayTickets(tickets);
609
+ }
610
+ } else {
611
+ console.error('Failed to load tickets:', data.error);
612
+ }
613
+ })
614
+ .catch(error => {
615
+ document.getElementById('tickets-loading').style.display = 'none';
616
+ console.error('Error loading tickets:', error);
617
+ });
618
+ }
619
+
620
+ function displayTickets(ticketsToShow) {
621
+ const container = document.getElementById('tickets-container');
622
+ container.innerHTML = '';
623
+
624
+ ticketsToShow.forEach(ticket => {
625
+ const ticketElement = createTicketElement(ticket);
626
+ container.appendChild(ticketElement);
627
+ });
628
+ }
629
+
630
+ function createTicketElement(ticket) {
631
+ const div = document.createElement('div');
632
+ div.className = 'ticket-item';
633
+ div.onclick = () => openTicketModal(ticket.ticket_number);
634
+
635
+ const createdDate = new Date(ticket.created_at).toLocaleDateString();
636
+
637
+ div.innerHTML = `
638
+ <div class="ticket-header">
639
+ <div class="ticket-number">${ticket.ticket_number}</div>
640
+ <div class="ticket-status status-${ticket.status}">${ticket.status.replace('_', ' ')}</div>
641
+ </div>
642
+ <div class="ticket-subject">${ticket.subject}</div>
643
+ <div class="ticket-meta">
644
+ <div>
645
+ <span class="ticket-category">${ticket.category}</span>
646
+ Priority: ${ticket.priority}
647
+ ${ticket.escalation_level > 0 ? `<span class="escalation-badge">Escalated L${ticket.escalation_level}</span>` : ''}
648
+ </div>
649
+ <div>Created: ${createdDate}</div>
650
+ </div>
651
+ `;
652
+
653
+ return div;
654
+ }
655
+
656
+ // Form submission
657
+ document.getElementById('create-ticket-form').addEventListener('submit', function(e) {
658
+ e.preventDefault();
659
+
660
+ const formData = new FormData(e.target);
661
+ const ticketData = {
662
+ subject: formData.get('subject'),
663
+ description: formData.get('description'),
664
+ priority: formData.get('priority'),
665
+ category: formData.get('category')
666
+ };
667
+
668
+ const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
669
+
670
+ fetch('/api/tickets/create', {
671
+ method: 'POST',
672
+ headers: {
673
+ 'Content-Type': 'application/json',
674
+ 'X-CSRFToken': csrfToken
675
+ },
676
+ body: JSON.stringify(ticketData)
677
+ })
678
+ .then(response => response.json())
679
+ .then(data => {
680
+ if (data.success) {
681
+ alert(`Ticket created successfully! Ticket number: ${data.ticket_number}`);
682
+ e.target.reset();
683
+ loadTickets(); // Refresh the tickets list
684
+ } else {
685
+ alert('Failed to create ticket: ' + data.error);
686
+ }
687
+ })
688
+ .catch(error => {
689
+ console.error('Error creating ticket:', error);
690
+ alert('Error creating ticket. Please try again.');
691
+ });
692
+ });
693
+
694
+ // Status filter
695
+ document.getElementById('status-filter').addEventListener('change', function(e) {
696
+ const status = e.target.value;
697
+ if (status === '') {
698
+ displayTickets(tickets);
699
+ } else {
700
+ const filtered = tickets.filter(ticket => ticket.status === status);
701
+ displayTickets(filtered);
702
+ }
703
+ });
704
+
705
+ function openTicketModal(ticketNumber) {
706
+ fetch(`/api/tickets/${ticketNumber}`)
707
+ .then(response => response.json())
708
+ .then(data => {
709
+ if (data.success) {
710
+ showTicketDetails(data.ticket, data.updates);
711
+ document.getElementById('update-ticket-id').value = data.ticket.id;
712
+
713
+ // Load SLA and escalation info
714
+ loadSLAInfo(data.ticket.id);
715
+ checkEscalationStatus(data.ticket.id);
716
+
717
+ document.getElementById('ticket-modal').style.display = 'flex';
718
+ } else {
719
+ alert('Failed to load ticket details: ' + data.error);
720
+ }
721
+ })
722
+ .catch(error => {
723
+ console.error('Error loading ticket:', error);
724
+ alert('Error loading ticket details.');
725
+ });
726
+ }
727
+
728
+ function loadSLAInfo(ticketId) {
729
+ fetch(`/api/tickets/${ticketId}/sla`)
730
+ .then(response => response.json())
731
+ .then(data => {
732
+ if (data.success && data.sla_metrics) {
733
+ showSLAStatus(data.sla_metrics);
734
+ }
735
+ })
736
+ .catch(error => console.error('Error loading SLA info:', error));
737
+ }
738
+
739
+ function showSLAStatus(sla) {
740
+ const slaSection = document.getElementById('sla-status');
741
+ let statusClass = 'sla-met';
742
+ let statusText = 'Within SLA';
743
+
744
+ if (!sla.sla_met) {
745
+ if (sla.sla_breach_hours > 0) {
746
+ statusClass = 'sla-breach';
747
+ statusText = `SLA Breached (${sla.sla_breach_hours.toFixed(1)}h over)`;
748
+ } else {
749
+ statusClass = 'sla-warning';
750
+ statusText = 'SLA at Risk';
751
+ }
752
+ }
753
+
754
+ slaSection.innerHTML = `
755
+ <h4>Service Level Agreement</h4>
756
+ <div class="sla-metric">
757
+ <span>Target Response Time:</span>
758
+ <span>${sla.sla_target_hours}h</span>
759
+ </div>
760
+ <div class="sla-metric">
761
+ <span>Hours Open:</span>
762
+ <span>${sla.hours_open.toFixed(1)}h</span>
763
+ </div>
764
+ <div class="sla-metric">
765
+ <span>Status:</span>
766
+ <span class="sla-status ${statusClass}">${statusText}</span>
767
+ </div>
768
+ ${sla.resolution_hours ? `
769
+ <div class="sla-metric">
770
+ <span>Resolution Time:</span>
771
+ <span>${sla.resolution_hours.toFixed(1)}h</span>
772
+ </div>` : ''}
773
+ `;
774
+ slaSection.style.display = 'block';
775
+ }
776
+
777
+ function checkEscalationStatus(ticketId) {
778
+ fetch(`/api/tickets/${ticketId}/escalation-check`)
779
+ .then(response => response.json())
780
+ .then(data => {
781
+ if (data.success) {
782
+ const escalationSection = document.getElementById('escalation-actions');
783
+ if (data.escalation_check.needs_escalation || data.escalation_check.status !== 'resolved') {
784
+ escalationSection.style.display = 'block';
785
+ window.currentTicketId = ticketId; // Store for escalation function
786
+ }
787
+ }
788
+ })
789
+ .catch(error => console.error('Error checking escalation:', error));
790
+ }
791
+
792
+ function escalateTicket() {
793
+ if (!window.currentTicketId) {
794
+ alert('No ticket selected for escalation');
795
+ return;
796
+ }
797
+
798
+ const reason = prompt('Please provide a reason for escalation:');
799
+ if (!reason) return;
800
+
801
+ fetch(`/api/tickets/${window.currentTicketId}/escalate`, {
802
+ method: 'POST',
803
+ headers: {
804
+ 'Content-Type': 'application/json',
805
+ },
806
+ body: JSON.stringify({
807
+ reason: reason
808
+ })
809
+ })
810
+ .then(response => response.json())
811
+ .then(data => {
812
+ if (data.success) {
813
+ alert('Ticket escalated successfully! Our team will prioritize your request.');
814
+ closeTicketModal();
815
+ loadTickets(); // Refresh the tickets list
816
+ } else {
817
+ alert('Failed to escalate ticket: ' + data.error);
818
+ }
819
+ })
820
+ .catch(error => {
821
+ console.error('Error escalating ticket:', error);
822
+ alert('Error escalating ticket. Please try again.');
823
+ });
824
+ }
825
+
826
+ function showTicketDetails(ticket, updates) {
827
+ const detailsContainer = document.getElementById('ticket-details');
828
+ const createdDate = new Date(ticket.created_at).toLocaleDateString();
829
+
830
+ let updatesHtml = '';
831
+ if (updates && updates.length > 0) {
832
+ updatesHtml = '<h4 style="margin-top: 2rem;">Updates:</h4>';
833
+ updates.forEach(update => {
834
+ const updateDate = new Date(update.created_at).toLocaleDateString();
835
+ updatesHtml += `
836
+ <div style="background: rgba(255,255,255,0.1); padding: 1rem; margin: 0.5rem 0; border-radius: 8px;">
837
+ <div style="font-size: 0.9rem; margin-bottom: 0.5rem;">
838
+ ${updateDate} - ${update.update_type}
839
+ </div>
840
+ <div>${update.message}</div>
841
+ </div>
842
+ `;
843
+ });
844
+ }
845
+
846
+ detailsContainer.innerHTML = `
847
+ <div>
848
+ <h4>Ticket ${ticket.ticket_number}</h4>
849
+ <p><strong>Status:</strong> <span class="ticket-status status-${ticket.status}">${ticket.status.replace('_', ' ')}</span></p>
850
+ <p><strong>Category:</strong> ${ticket.category}</p>
851
+ <p><strong>Priority:</strong> ${ticket.priority}</p>
852
+ <p><strong>Created:</strong> ${createdDate}</p>
853
+ <h5 style="margin-top: 1.5rem;">Subject:</h5>
854
+ <p>${ticket.subject}</p>
855
+ <h5 style="margin-top: 1.5rem;">Description:</h5>
856
+ <p style="white-space: pre-wrap;">${ticket.description}</p>
857
+ ${updatesHtml}
858
+ </div>
859
+ `;
860
+
861
+ document.getElementById('ticket-modal-title').textContent = `Ticket ${ticket.ticket_number}`;
862
+
863
+ // Force inline styles on modal content to avoid external CSS conflicts
864
+ const modalContent = document.querySelector('#ticket-modal .modal-content');
865
+ if (modalContent) {
866
+ modalContent.style.backgroundColor = 'rgba(255,255,255,0.98)';
867
+ modalContent.style.color = '#1a202c';
868
+ }
869
+ }
870
+
871
+ function closeTicketModal() {
872
+ document.getElementById('ticket-modal').style.display = 'none';
873
+ document.getElementById('update-message').value = '';
874
+ }
875
+
876
+ // Update form submission
877
+ document.getElementById('update-ticket-form').addEventListener('submit', function(e) {
878
+ e.preventDefault();
879
+
880
+ const ticketId = document.getElementById('update-ticket-id').value;
881
+ const message = document.getElementById('update-message').value;
882
+
883
+ fetch(`/api/tickets/${ticketId}/update`, {
884
+ method: 'POST',
885
+ headers: {
886
+ 'Content-Type': 'application/json',
887
+ },
888
+ body: JSON.stringify({
889
+ message: message,
890
+ update_type: 'note'
891
+ })
892
+ })
893
+ .then(response => {
894
+ console.log('Response received, status:', response.status);
895
+ // Parse JSON regardless of status
896
+ return response.json().then(data => ({ data, status: response.status, ok: response.ok }));
897
+ })
898
+ .then(({ data, status, ok }) => {
899
+ console.log('JSON parsed, data:', data);
900
+
901
+ if (!ok) {
902
+ const errorMsg = data.error || `Server error: ${status}`;
903
+ alert('Failed to add update: ' + errorMsg);
904
+ return;
905
+ }
906
+
907
+ if (data.success) {
908
+ alert('Update added successfully!');
909
+ document.getElementById('update-message').value = '';
910
+ // Reload the ticket details
911
+ const ticketNumber = document.getElementById('ticket-modal-title').textContent.replace('Ticket ', '');
912
+ openTicketModal(ticketNumber);
913
+ } else {
914
+ alert('Failed to add update: ' + (data.error || 'Unknown error'));
915
+ }
916
+ })
917
+ .catch(error => {
918
+ console.error('Error adding update:', error);
919
+ console.error('Error details:', error.message);
920
+ alert('Error adding update: ' + error.message);
921
+ });
922
+ });
923
+
924
+ // Function to show login modal (assuming it exists in base template)
925
+ function showLoginModal() {
926
+ // This should trigger the login modal from the base template
927
+ const authBtn = document.getElementById('auth-btn');
928
+ if (authBtn && authBtn.textContent === 'Login') {
929
+ authBtn.click();
930
+ }
931
+ }
932
+
933
+ // Close modal on outside click
934
+ document.getElementById('ticket-modal').addEventListener('click', function(e) {
935
+ if (e.target === this) {
936
+ closeTicketModal();
937
+ }
938
+ });
939
+ </script>
940
+ {% endblock %}