<!DOCTYPE html>
<html lang="hi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hair Cutting Salon Reminder</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #0f2027 0%, #203a43 50%, #2c5364 100%);
color: #333;
min-height: 100vh;
padding: 20px;
margin: 0;
}
.app-container {
max-width: 100%;
margin: 0 auto;
background: rgba(255, 255, 255, 0.95);
min-height: 90vh;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 0 30px rgba(0,0,0,0.3);
position: relative;
}
.diamond-pattern {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:
linear-gradient(135deg, rgba(76, 161, 175, 0.05) 25%, transparent 25%) -50px 0,
linear-gradient(225deg, rgba(76, 161, 175, 0.05) 25%, transparent 25%) -50px 0,
linear-gradient(315deg, rgba(76, 161, 175, 0.05) 25%, transparent 25%),
linear-gradient(45deg, rgba(76, 161, 175, 0.05) 25%, transparent 25%);
background-size: 20px 20px;
z-index: 0;
opacity: 0.3;
}
.header {
background: linear-gradient(135deg, #4ca1af 0%, #2c3e50 100%);
color: white;
padding: 20px 15px;
text-align: center;
position: relative;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
z-index: 1;
}
.header h1 {
font-size: 1.5rem;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.notification-badge {
position: absolute;
top: 15px;
right: 15px;
background: #ff4757;
color: white;
border-radius: 50%;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: bold;
}
.tabs {
display: flex;
background: #2c3e50;
position: sticky;
top: 0;
z-index: 10;
}
.tab {
flex: 1;
text-align: center;
padding: 15px;
color: white;
font-weight: 500;
border-bottom: 3px solid transparent;
transition: all 0.3s;
cursor: pointer;
position: relative;
overflow: hidden;
}
.tab::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 0;
background: rgba(76, 161, 175, 0.3);
transition: all 0.3s;
transform: translateX(-50%);
border-radius: 50%;
}
.tab:hover::after {
width: 120%;
height: 120%;
}
.tab.active {
border-bottom: 3px solid #4ca1af;
background: rgba(76, 161, 175, 0.2);
}
.tab i {
margin-right: 5px;
}
.content {
padding: 20px;
display: none;
min-height: 500px;
position: relative;
z-index: 1;
}
.content.active {
display: block;
}
.card {
background: white;
border-radius: 15px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 5px 15px rgba(0,0,0,0.05);
position: relative;
overflow: hidden;
transition: transform 0.3s, box-shadow 0.3s;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 20px rgba(0,0,0,0.1);
}
.card::before {
content: '';
position: absolute;
top: -10px;
right: -10px;
width: 30px;
height: 30px;
background: linear-gradient(135deg, #4ca1af 0%, #2c3e50 100%);
transform: rotate(45deg);
opacity: 0.1;
}
.card-title {
font-size: 1.2rem;
color: #2c3e50;
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.form-group {
margin-bottom: 15px;
position: relative;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: 500;
color: #2c3e50;
}
.form-control {
width: 100%;
padding: 12px 15px;
border: 1px solid #ddd;
border-radius: 8px;
font-size: 16px;
transition: all 0.3s;
}
.form-control:focus {
border-color: #4ca1af;
outline: none;
box-shadow: 0 0 0 3px rgba(76, 161, 175, 0.2);
}
.btn {
display: block;
width: 100%;
padding: 15px;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
text-align: center;
cursor: pointer;
transition: all 0.3s;
margin-top: 10px;
position: relative;
overflow: hidden;
}
.btn::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.3s, height 0.3s;
}
.btn:hover::after {
width: 300px;
height: 300px;
}
.btn-primary {
background: linear-gradient(135deg, #4ca1af 0%, #2c3e50 100%);
color: white;
}
.btn-whatsapp {
background: linear-gradient(135deg, #25D366 0%, #128C7E 100%);
color: white;
}
.btn-call {
background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%);
color: white;
}
.btn-danger {
background: linear-gradient(135deg, #ff4757 0%, #ff3838 100%);
color: white;
}
.btn-edit {
background: linear-gradient(135deg, #ffa502 0%, #ff7f00 100%);
color: white;
}
.customer-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
border-bottom: 1px solid #eee;
transition: background 0.3s;
border-radius: 8px;
margin-bottom: 10px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
.customer-item:hover {
background: #f9f9f9;
}
.customer-info h3 {
font-size: 1.1rem;
color: #2c3e50;
margin-bottom: 5px;
}
.customer-info p {
font-size: 0.9rem;
color: #666;
margin-bottom: 3px;
}
.customer-actions {
display: flex;
gap: 10px;
}
.action-btn {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: none;
color: white;
font-size: 16px;
cursor: pointer;
transition: transform 0.3s;
}
.action-btn:hover {
transform: scale(1.1);
}
/* Reminder status colors */
.reminder-item {
padding: 15px;
border-radius: 12px;
margin-bottom: 15px;
box-shadow: 0 4px 10px rgba(0,0,0,0.08);
border-left: 4px solid #ffc107;
background: #fff9e6;
transition: transform 0.3s;
}
.reminder-item:hover {
transform: translateX(5px);
}
.reminder-item.urgent {
border-left: 4px solid #ff4757;
background: #fff5f5;
}
.reminder-item.normal {
border-left: 4px solid #2ecc71;
background: #f0fff4;
}
.reminder-item.warning {
border-left: 4px solid #ffa502;
background: #fff9e6;
}
.reminder-item h3 {
color: #2c3e50;
margin-bottom: 8px;
display: flex;
align-items: center;
justify-content: space-between;
}
.reminder-status {
font-size: 0.7rem;
padding: 3px 10px;
border-radius: 20px;
font-weight: bold;
}
.status-urgent {
background: #ff4757;
color: white;
}
.status-normal {
background: #2ecc71;
color: white;
}
.status-warning {
background: #ffa502;
color: white;
}
.reminder-item p {
color: #666;
margin-bottom: 5px;
font-size: 0.9rem;
}
.stats-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
margin-bottom: 20px;
}
.stat-card {
background: white;
border-radius: 12px;
padding: 15px;
text-align: center;
box-shadow: 0 4px 8px rgba(0,0,0,0.05);
position: relative;
overflow: hidden;
transition: transform 0.3s;
}
.stat-card:hover {
transform: translateY(-5px);
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(135deg, #4ca1af 0%, #2c3e50 100%);
}
.stat-number {
font-size: 1.8rem;
font-weight: bold;
color: #4ca1af;
margin: 10px 0;
}
.stat-label {
font-size: 0.9rem;
color: #666;
}
.notification {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: #2ecc71;
color: white;
padding: 15px 20px;
border-radius: 50px;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
display: flex;
align-items: center;
gap: 10px;
z-index: 1000;
opacity: 0;
transition: opacity 0.3s;
}
.notification.show {
opacity: 1;
}
.empty-state {
text-align: center;
padding: 40px 20px;
color: #666;
}
.empty-state i {
font-size: 3rem;
color: #ddd;
margin-bottom: 15px;
}
.settings-btn {
position: absolute;
top: 15px;
left: 15px;
background: rgba(255, 255, 255, 0.2);
color: white;
border: none;
border-radius: 50%;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 18px;
transition: transform 0.3s;
}
.settings-btn:hover {
transform: rotate(45deg);
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
align-items: center;
justify-content: center;
backdrop-filter: blur(5px);
}
.modal-content {
background: white;
border-radius: 15px;
padding: 20px;
width: 90%;
max-width: 450px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
max-height: 90vh;
overflow-y: auto;
position: relative;
}
.modal-content::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 5px;
background: linear-gradient(135deg, #4ca1af 0%, #2c3e50 100%);
border-radius: 15px 15px 0 0;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.modal-title {
font-size: 1.3rem;
color: #2c3e50;
}
.close-btn {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: #666;
transition: transform 0.3s;
}
.close-btn:hover {
transform: rotate(90deg);
}
.service-history {
margin-top: 15px;
padding-top: 15px;
border-top: 1px solid #eee;
}
.service-history-item {
padding: 10px;
background: #f9f9f9;
border-radius: 8px;
margin-bottom: 10px;
font-size: 0.9rem;
}
.language-switcher {
position: absolute;
top: 15px;
right: 50px;
}
.language-btn {
background: rgba(255, 255, 255, 0.2);
color: white;
border: none;
border-radius: 20px;
padding: 5px 15px;
cursor: pointer;
font-size: 14px;
display: flex;
align-items: center;
gap: 5px;
transition: all 0.3s;
z-index: 2;
}
.language-btn:hover {
background: rgba(255, 255, 255, 0.3);
}
.sort-options {
display: flex;
gap: 10px;
margin-bottom: 15px;
flex-wrap: wrap;
}
.sort-btn {
padding: 8px 15px;
border: 1px solid #ddd;
border-radius: 20px;
background: white;
cursor: pointer;
transition: all 0.3s;
font-size: 0.9rem;
}
.sort-btn.active {
background: #4ca1af;
color: white;
border-color: #4ca1af;
}
.language-selector-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
align-items: center;
justify-content: center;
}
.language-option {
padding: 15px;
margin: 10px 0;
background: white;
border-radius: 8px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.language-option:hover {
background: #f0f0f0;
}
@media (max-width: 768px) {
body {
padding: 10px;
}
.app-container {
min-height: 95vh;
border-radius: 15px;
}
.stats-container {
grid-template-columns: 1fr;
}
.language-switcher {
right: 60px;
top: 18px;
}
.language-btn {
padding: 3px 10px;
font-size: 12px;
}
}
.error-message {
color: #ff4757;
font-size: 0.8rem;
margin-top: 5px;
display: none;
}
.form-group.error input,
.form-group.error select {
border-color: #ff4757;
}
.diamond-shape {
width: 15px;
height: 15px;
background: linear-gradient(135deg, #4ca1af 0%, #2c3e50 100%);
transform: rotate(45deg);
display: inline-block;
margin-right: 8px;
}
.version-info {
position: absolute;
bottom: 10px;
right: 15px;
font-size: 0.7rem;
color: #888;
}
/* Styles for the new download button */
.btn-download {
background: linear-gradient(135deg, #1abc9c 0%, #16a085 100%);
color: white;
margin-top: 10px;
font-size: 14px;
}
/* Added new styling for the message editor modal */
#whatsappMessageText {
min-height: 200px;
}
</style>
</head>
<body>
<div class="app-container">
<div class="diamond-pattern"></div>
<div class="header">
<button class="settings-btn" id="settingsBtn">
<i class="fas fa-cog"></i>
</button>
<div class="language-switcher">
<button class="language-btn" id="languageBtn">
<i class="fas fa-language"></i> <span id="languageText">EN</span>
</button>
</div>
<h1><span class="diamond-shape"></span> <span id="shopName">Hair Cutting Salon</span></h1>
<div class="notification-badge" id="notificationBadge">0</div>
</div>
<div class="tabs">
<div class="tab active" data-tab="home">
<i class="fas fa-home"></i> <span class="lang-home">Home</span>
</div>
<div class="tab" data-tab="customers">
<i class="fas fa-users"></i> <span class="lang-customers">Customers</span>
</div>
<div class="tab" data-tab="reminders">
<i class="fas fa-bell"></i> <span class="lang-reminders">Reminders</span>
</div>
</div>
<div class="content active" id="homeContent">
<div class="stats-container">
<div class="stat-card">
<i class="fas fa-users" style="color: #4ca1af;"></i>
<div class="stat-number" id="totalCustomers">0</div>
<div class="stat-label lang-total-customers">Total Customers</div>
</div>
<div class="stat-card">
<i class="fas fa-bell" style="color: #ffc107;"></i>
<div class="stat-number" id="upcomingReminders">0</div>
<div class="stat-label lang-upcoming-reminders">Need Hair Cut</div>
</div>
<div class="stat-card">
<i class="fas fa-calendar-check" style="color: #2ecc71;"></i>
<div class="stat-number" id="servicesThisMonth">0</div>
<div class="stat-label lang-this-month">This Month</div>
</div>
<div class="stat-card">
<i class="fas fa-phone" style="color: #25D366;"></i>
<div class="stat-number" id="callsToday">0</div>
<div class="stat-label lang-today-calls">Today's Reminders</div>
</div>
</div>
<div class="card">
<h2 class="card-title"><i class="fas fa-plus-circle"></i> <span class="lang-add-customer">Add New Customer</span></h2>
<form id="customerForm">
<div class="form-group">
<label for="customerName" class="lang-customer-name">Customer Name *</label>
<input type="text" class="form-control" id="customerName" required>
</div>
<div class="form-group">
<label for="customerPhone" class="lang-phone-number">Phone Number *</label>
<input type="tel" class="form-control" id="customerPhone" required>
<div class="error-message" id="phoneError">This phone number already exists</div>
</div>
<div class="form-group">
<label for="washDate" class="lang-service-date">Last Hair Cut Date *</label>
<input type="date" class="form-control" id="washDate" required>
</div>
<button type="submit" class="btn btn-primary" id="addCustomerBtn">
<i class="fas fa-save"></i> <span class="lang-add-customer-btn">Add Customer</span>
</button>
</form>
</div>
<div class="card">
<h2 class="card-title"><i class="fas fa-history"></i> <span class="lang-recent-services">Recent Hair Cuts</span></h2>
<div id="recentServices">
<div class="empty-state">
<i class="fas fa-users-slash"></i>
<p class="lang-no-customers">No customers added yet</p>
</div>
</div>
</div>
</div>
<div class="content" id="customersContent">
<div class="card">
<h2 class="card-title"><i class="fas fa-users"></i> <span class="lang-all-customers">All Customers</span></h2>
<div class="form-group">
<input type="text" class="form-control" id="searchCustomer" placeholder="Search customers...">
</div>
<button class="btn btn-download" id="downloadBtn">
<i class="fas fa-download"></i> <span class="lang-download-data">Download Data (Excel)</span>
</button>
</div>
<div id="customersList">
<div class="empty-state">
<i class="fas fa-users-slash"></i>
<p class="lang-no-customers">No customers added yet</p>
</div>
</div>
</div>
<div class="content" id="remindersContent">
<div class="card">
<h2 class="card-title"><i class="fas fa-bell"></i> <span class="lang-upcoming-reminders">Upcoming Reminders</span></h2>
<p class="lang-reminders-description">Customers are automatically sorted by reminder urgency:</p>
<div class="sort-options">
<button class="sort-btn active" data-sort="urgency">
<i class="fas fa-exclamation-circle"></i> Sort by Urgency
</button>
<button class="sort-btn" data-sort="date">
<i class="fas fa-calendar"></i> Sort by Date
</button>
</div>
</div>
<div id="remindersList">
<div class="empty-state">
<i class="fas fa-bell-slash"></i>
<p class="lang-no-reminders">No reminders yet</p>
</div>
</div>
</div>
<div class="notification" id="notification">
<i class="fas fa-check-circle"></i>
<span id="notificationText">Customer added successfully!</span>
</div>
<div class="version-info">v2.1.0</div>
</div>
<div class="modal" id="settingsModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title"><i class="fas fa-cog"></i> <span class="lang-shop-settings">Salon Settings</span></h3>
<button class="close-btn">×</button>
</div>
<form id="shopSettingsForm">
<div class="form-group">
<label for="shopNameInput" class="lang-shop-name">Salon Name *</label>
<input type="text" class="form-control" id="shopNameInput" required>
</div>
<div class="form-group">
<label for="shopPhoneInput" class="lang-shop-phone">Salon Phone Number *</label>
<input type="tel" class="form-control" id="shopPhoneInput" required>
</div>
<div class="form-group">
<label for="reminderDays" class="lang-reminder-days">Reminder (days before) *</label>
<input type="number" class="form-control" id="reminderDays" value="20" min="1" max="90" required>
</div>
<button type="submit" class="btn btn-primary lang-save-settings">Save Settings</button>
</form>
</div>
</div>
<div class="modal" id="languageSelectorModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title"><i class="fas fa-language"></i> Select Message Language</h3>
<button class="close-btn">×</button>
</div>
<div id="languageOptions">
<div class="language-option" data-lang="english">
<i class="fas fa-language"></i> English
</div>
<div class="language-option" data-lang="hindi">
<i class="fas fa-language"></i> Hindi
</div>
<div class="language-option" data-lang="punjabi">
<i class="fas fa-language"></i> Punjabi
</div>
</div>
</div>
</div>
<div class="modal" id="editCustomerModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title"><i class="fas fa-user-edit"></i> Edit Customer</h3>
<button class="close-btn">×</button>
</div>
<form id="editCustomerForm">
<input type="hidden" id="editCustomerId">
<div class="form-group">
<label for="editCustomerName">Customer Name</label>
<input type="text" class="form-control" id="editCustomerName" required>
</div>
<div class="form-group">
<label for="editCustomerPhone">Phone Number</label>
<input type="tel" class="form-control" id="editCustomerPhone" required>
<div class="error-message" id="editPhoneError">This phone number already exists</div>
</div>
<div class="form-group">
<label for="editWashDate">Last Hair Cut Date</label>
<input type="date" class="form-control" id="editWashDate" required>
</div>
<button type="submit" class="btn btn-primary">Save Changes</button>
</form>
</div>
</div>
<div class="modal" id="messageEditorModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title"><i class="fab fa-whatsapp"></i> Edit WhatsApp Message</h3>
<button class="close-btn" id="closeMessageEditor">×</button>
</div>
<div class="form-group">
<label for="whatsappMessageText">Message Content:</label>
<textarea id="whatsappMessageText" class="form-control" rows="10"></textarea>
</div>
<button class="btn btn-whatsapp" id="sendWhatsAppBtn"><i class="fab fa-whatsapp"></i> Send on WhatsApp</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM elements
const settingsBtn = document.getElementById('settingsBtn');
const settingsModal = document.getElementById('settingsModal');
const languageSelectorModal = document.getElementById('languageSelectorModal');
const editCustomerModal = document.getElementById('editCustomerModal');
const messageEditorModal = document.getElementById('messageEditorModal');
const whatsappMessageText = document.getElementById('whatsappMessageText');
const sendWhatsAppBtn = document.getElementById('sendWhatsAppBtn');
const closeButtons = document.querySelectorAll('.close-btn');
const closeMessageEditorBtn = document.getElementById('closeMessageEditor');
const shopSettingsForm = document.getElementById('shopSettingsForm');
const shopNameInput = document.getElementById('shopNameInput');
const shopPhoneInput = document.getElementById('shopPhoneInput');
const reminderDaysInput = document.getElementById('reminderDays');
const shopNameElement = document.getElementById('shopName');
const customerForm = document.getElementById('customerForm');
const notification = document.getElementById('notification');
const notificationText = document.getElementById('notificationText');
const searchInput = document.getElementById('searchCustomer');
const phoneError = document.getElementById('phoneError');
const languageBtn = document.getElementById('languageBtn');
const languageText = document.getElementById('languageText');
const sortButtons = document.querySelectorAll('.sort-btn');
const languageOptions = document.querySelectorAll('.language-option');
const downloadBtn = document.getElementById('downloadBtn');
// Tab navigation
const tabs = document.querySelectorAll('.tab');
const contents = document.querySelectorAll('.content');
// Edit form elements
const editCustomerForm = document.getElementById('editCustomerForm');
const editCustomerIdInput = document.getElementById('editCustomerId');
const editCustomerNameInput = document.getElementById('editCustomerName');
const editCustomerPhoneInput = document.getElementById('editCustomerPhone');
const editWashDateInput = document.getElementById('editWashDate');
// Data storage and DB initialization
let db;
let shopSettings = JSON.parse(localStorage.getItem('shopSettings')) || {
name: 'Hair Cutting Salon',
phone: '',
reminderDays: 20
};
let currentLanguage = localStorage.getItem('language') || 'hi';
let selectedMessageLanguage = 'hindi';
let currentCustomerIdForMessage = null;
// Language translations
const translations = {
'en': {
'home': 'Home',
'customers': 'Customers',
'reminders': 'Reminders',
'total-customers': 'Total Customers',
'upcoming-reminders': 'Need Hair Cut',
'this-month': 'This Month',
'today-calls': "Today's Reminders",
'add-customer': 'Add New Customer',
'customer-name': 'Customer Name *',
'phone-number': 'Phone Number *',
'service-date': 'Last Hair Cut Date *',
'add-customer-btn': 'Add Customer',
'recent-services': 'Recent Hair Cuts',
'no-customers': 'No customers added yet',
'all-customers': 'All Customers',
'search-customers': 'Search customers...',
'reminders-description': 'Customers are automatically sorted by reminder urgency:',
'no-reminders': 'No reminders yet',
'shop-settings': 'Salon Settings',
'shop-name': 'Salon Name *',
'shop-phone': 'Salon Phone Number *',
'reminder-days': 'Reminder (days before) *',
'save-settings': 'Save Settings',
'whatsapp': 'WhatsApp',
'call': 'Call',
'days-since-service': 'days since last service',
'download-data': 'Download Data (Excel)',
'no-customers-found': 'No customers found'
},
'hi': {
'home': 'होम',
'customers': 'ग्राहक',
'reminders': 'रिमाइंडर',
'total-customers': 'कुल ग्राहक',
'upcoming-reminders': 'हेयर कट की जरूरत',
'this-month': 'इस महीने',
'today-calls': 'आज के रिमाइंडर',
'add-customer': 'नया ग्राहक जोड़ें',
'customer-name': 'ग्राहक का नाम *',
'phone-number': 'फोन नंबर *',
'service-date': 'आखिरी हेयर कट की तारीख *',
'add-customer-btn': 'ग्राहक जोड़ें',
'recent-services': 'हाल के हेयर कट',
'no-customers': 'अभी तक कोई ग्राहक नहीं जोड़ा गया है',
'all-customers': 'सभी ग्राहक',
'search-customers': 'ग्राहक खोजें...',
'reminders-description': 'ग्राहकों को स्वचालित रूप से रिमाइंडर की जरूरत के अनुसार क्रमबद्ध किया गया है:',
'no-reminders': 'अभी तक कोई रिमाइंडर नहीं है',
'shop-settings': 'सैलून सेटिंग्स',
'shop-name': 'सैलून का नाम *',
'shop-phone': 'सैलून का फोन नंबर *',
'reminder-days': 'रिमाइंडर (दिन पहले) *',
'save-settings': 'सेटिंग्स सहेजें',
'whatsapp': 'व्हाट्सएप',
'call': 'कॉल',
'days-since-service': 'दिन हो गए हैं',
'download-data': 'डेटा डाउनलोड करें (एक्सेल)',
'no-customers-found': 'कोई ग्राहक नहीं मिला'
},
'pa': {
'home': 'ਹੋਮ',
'customers': 'ਗ੍ਰਾਹਕ',
'reminders': 'ਰਿਮਾਇੰਡਰ',
'total-customers': 'ਕੁੱਲ ਗ੍ਰਾਹਕ',
'upcoming-reminders': 'ਹੇਅਰ ਕੱਟ ਦੀ ਲੋੜ',
'this-month': 'ਇਸ ਮਹੀਨੇ',
'today-calls': 'ਅੱਜ ਦੇ ਰਿਮਾਇੰਡਰ',
'add-customer': 'ਨਵਾਂ ਗ੍ਰਾਹਕ ਜੋੜੋ',
'customer-name': 'ਗ੍ਰਾਹਕ ਦਾ ਨਾਮ *',
'phone-number': 'ਫ਼ੋਨ ਨੰਬਰ *',
'service-date': 'ਆਖਰੀ ਹੇਅਰ ਕੱਟ ਦੀ ਮਿਤੀ *',
'add-customer-btn': 'ਗ੍ਰਾਹਕ ਜੋੜੋ',
'recent-services': 'ਹਾਲੀਆ ਹੇਅਰ ਕੱਟ',
'no-customers': 'ਹਾਲੇ ਤੱਕ ਕੋਈ ਗ੍ਰਾਹਕ ਨਹੀਂ ਜੋੜਿਆ ਗਿਆ',
'all-customers': 'ਸਾਰੇ ਗ੍ਰਾਹਕ',
'search-customers': 'ਗ੍ਰਾਹਕ ਖੋਜੋ...',
'reminders-description': 'ਗ੍ਰਾਹਕਾਂ ਨੂੰ ਰਿਮਾਇੰਡਰ ਦੀ ਤੁਰੰਤ ਲੋੜ ਅਨੁਸਾਰ ਆਪਣੇ ਆਪ ਛਾਂਟਿਆ ਜਾਂਦਾ ਹੈ:',
'no-reminders': 'ਹਾਲੇ ਤੱਕ ਕੋਈ ਰਿਮਾਇੰਡਰ ਨਹੀਂ',
'shop-settings': 'ਸੈਲੂਨ ਸੈਟਿੰਗਜ਼',
'shop-name': 'ਸੈਲੂਨ ਦਾ ਨਾਮ *',
'shop-phone': 'ਸੈਲੂਨ ਦਾ ਫੋਨ ਨੰਬਰ *',
'reminder-days': 'ਰਿਮਾਇੰਡਰ (ਦਿਨ ਪਹਿਲਾਂ) *',
'save-settings': 'ਸੈਟਿੰਗਜ਼ ਸੇਵ ਕਰੋ',
'whatsapp': 'ਵਾਟਸਐਪ',
'call': 'ਕਾਲ ਕਰੋ',
'days-since-service': 'ਦਿਨ ਹੋ ਗਏ ਹਨ',
'download-data': 'ਡੇਟਾ ਡਾਊਨਲੋਡ ਕਰੋ (ਐਕਸਲ)',
'no-customers-found': 'ਕੋਈ ਗਾਹਕ ਨਹੀਂ ਮਿਲਿਆ'
}
};
// IndexedDB Initialization
function initDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open("salonDB", 1);
request.onerror = (event) => {
console.error("IndexedDB error:", event.target.error);
reject("Database failed to open");
};
request.onupgradeneeded = (event) => {
db = event.target.result;
const objectStore = db.createObjectStore("customers", { keyPath: "id", autoIncrement: true });
objectStore.createIndex("phone", "phone", { unique: true });
objectStore.createIndex("name", "name", { unique: false });
objectStore.createIndex("lastServiceDate", "lastServiceDate", { unique: false });
};
request.onsuccess = (event) => {
db = event.target.result;
console.log("Database initialized successfully.");
resolve(db);
};
});
}
async function addCustomerToDB(customer) {
const transaction = db.transaction(["customers"], "readwrite");
const objectStore = transaction.objectStore("customers");
const request = objectStore.add(customer);
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async function updateCustomerInDB(customer) {
const transaction = db.transaction(["customers"], "readwrite");
const objectStore = transaction.objectStore("customers");
const request = objectStore.put(customer);
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async function deleteCustomerFromDB(id) {
const transaction = db.transaction(["customers"], "readwrite");
const objectStore = transaction.objectStore("customers");
const request = objectStore.delete(id);
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
async function getCustomersFromDB(searchTerm = '') {
const transaction = db.transaction(["customers"], "readonly");
const objectStore = transaction.objectStore("customers");
const customers = [];
return new Promise((resolve, reject) => {
objectStore.openCursor().onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
if (!searchTerm || cursor.value.name.toLowerCase().includes(searchTerm.toLowerCase()) || cursor.value.phone.includes(searchTerm)) {
customers.push(cursor.value);
}
cursor.continue();
} else {
resolve(customers);
}
};
transaction.onerror = (event) => reject(event.target.error);
});
}
async function getCustomerByPhone(phone) {
const transaction = db.transaction(["customers"], "readonly");
const objectStore = transaction.objectStore("customers");
const phoneIndex = objectStore.index("phone");
const request = phoneIndex.get(phone);
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// Function to get a single customer by ID
async function getCustomerFromDB(id) {
const transaction = db.transaction(["customers"], "readonly");
const objectStore = transaction.objectStore("customers");
const request = objectStore.get(id);
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// Initialize the app
async function initApp() {
try {
await initDB();
// Load shop settings
if (shopSettings) {
shopNameInput.value = shopSettings.name;
shopPhoneInput.value = shopSettings.phone;
reminderDaysInput.value = shopSettings.reminderDays;
shopNameElement.textContent = shopSettings.name;
}
// Set current date as default for wash date
const today = new Date();
const formattedDate = today.toISOString().split('T')[0];
document.getElementById('washDate').value = formattedDate;
// Load customers
renderCustomers();
updateStats();
renderReminders();
// Set up event listeners
setupEventListeners();
// Apply language
applyLanguage(currentLanguage);
// Start the automatic reminder check
startReminderScheduler();
} catch (error) {
console.error("App initialization failed:", error);
}
}
// Function to check for and send automatic reminders
async function startReminderScheduler() {
const reminderInterval = 24 * 60 * 60 * 1000; // Check once a day
// Run the check immediately
sendAutomaticReminders();
// Set up a daily timer for the check
setInterval(sendAutomaticReminders, reminderInterval);
}
async function sendAutomaticReminders() {
const now = new Date();
const reminderDays = shopSettings.reminderDays || 20;
const customers = await getCustomersFromDB();
customers.forEach(customer => {
const lastServiceDate = new Date(customer.lastServiceDate);
const timeDiff = now.getTime() - lastServiceDate.getTime();
const daysDiff = Math.floor(timeDiff / (1000 * 3600 * 24));
if (daysDiff === reminderDays) {
const lastReminderSent = localStorage.getItem(`lastReminderSent_${customer.id}`);
const lastReminderDate = lastReminderSent ? new Date(lastReminderSent) : null;
if (!lastReminderDate || lastReminderDate.toDateString() !== now.toDateString()) {
const defaultMessage = getDefaultMessage(customer.name, selectedMessageLanguage);
// We are not actually sending here, just logging to console
console.log(`Auto reminder for ${customer.name}: ${defaultMessage}`);
localStorage.setItem(`lastReminderSent_${customer.id}`, now.toISOString());
}
}
});
}
// Apply language to the UI
function applyLanguage(lang) {
const elements = document.querySelectorAll('[class^="lang-"]');
elements.forEach(element => {
const key = element.className.replace('lang-', '');
if (translations[lang] && translations[lang][key]) {
element.textContent = translations[lang][key];
}
});
// Update placeholders
document.getElementById('searchCustomer').placeholder = translations[lang]['search-customers'];
// Update language button text
languageText.textContent = lang === 'en' ? 'HI' : 'EN';
}
// Set up event listeners
function setupEventListeners() {
// Tab navigation
tabs.forEach(tab => {
tab.addEventListener('click', function() {
const tabName = this.getAttribute('data-tab');
// Deactivate all tabs and content
tabs.forEach(t => t.classList.remove('active'));
contents.forEach(c => c.classList.remove('active'));
// Activate current tab and content
this.classList.add('active');
document.getElementById(tabName + 'Content').classList.add('active');
// If reminders tab, refresh reminders
if (tabName === 'reminders') {
renderReminders();
} else if (tabName === 'customers') {
renderCustomers();
}
});
});
// Language switcher
languageBtn.addEventListener('click', function() {
currentLanguage = currentLanguage === 'en' ? 'hi' : 'en';
localStorage.setItem('language', currentLanguage);
applyLanguage(currentLanguage);
});
// Settings modal
settingsBtn.addEventListener('click', function() {
settingsModal.style.display = 'flex';
});
// Close modals
closeButtons.forEach(btn => {
btn.addEventListener('click', function() {
settingsModal.style.display = 'none';
languageSelectorModal.style.display = 'none';
editCustomerModal.style.display = 'none';
});
});
// Close message editor modal specifically
closeMessageEditorBtn.addEventListener('click', () => {
messageEditorModal.style.display = 'none';
});
// Shop settings form
shopSettingsForm.addEventListener('submit', function(e) {
e.preventDefault();
shopSettings = {
name: shopNameInput.value,
phone: shopPhoneInput.value,
reminderDays: parseInt(reminderDaysInput.value)
};
localStorage.setItem('shopSettings', JSON.stringify(shopSettings));
shopNameElement.textContent = shopSettings.name;
showNotification(currentLanguage === 'en' ? 'Settings saved successfully!' : 'सेटिंग्स सफलतापूर्वक सहेजी गईं!');
settingsModal.style.display = 'none';
});
// Customer form
customerForm.addEventListener('submit', async function(e) {
e.preventDefault();
const name = document.getElementById('customerName').value;
const phone = document.getElementById('customerPhone').value;
const date = document.getElementById('washDate').value;
// Check if phone number already exists
const existingCustomer = await getCustomerByPhone(phone);
if (existingCustomer) {
phoneError.style.display = 'block';
document.getElementById('customerPhone').parentElement.classList.add('error');
return;
}
const newCustomer = {
name,
phone,
lastServiceDate: date,
createdAt: new Date().toISOString(),
};
try {
await addCustomerToDB(newCustomer);
showNotification(currentLanguage === 'en' ? `${name} added successfully!` : `${name} सफलतापूर्वक जोड़ा गया!`);
customerForm.reset();
// Reset error state
phoneError.style.display = 'none';
document.getElementById('customerPhone').parentElement.classList.remove('error');
// Set current date
const today = new Date();
const formattedDate = today.toISOString().split('T')[0];
document.getElementById('washDate').value = formattedDate;
renderCustomers();
updateStats();
renderReminders();
} catch (error) {
console.error("Failed to add customer:", error);
showNotification(currentLanguage === 'en' ? 'Failed to add customer.' : 'ग्राहक जोड़ने में विफल रहा।');
}
});
// Phone number validation
document.getElementById('customerPhone').addEventListener('input', async function() {
const phone = this.value;
const existingCustomer = await getCustomerByPhone(phone);
if (existingCustomer) {
phoneError.style.display = 'block';
this.parentElement.classList.add('error');
} else {
phoneError.style.display = 'none';
this.parentElement.classList.remove('error');
}
});
// Search functionality
searchInput.addEventListener('input', function() {
renderCustomers(this.value);
});
// Sort buttons
sortButtons.forEach(btn => {
btn.addEventListener('click', function() {
sortButtons.forEach(b => b.classList.remove('active'));
this.classList.add('active');
renderReminders(this.getAttribute('data-sort'));
});
});
// Language options for WhatsApp messages
languageOptions.forEach(option => {
option.addEventListener('click', function() {
selectedMessageLanguage = this.getAttribute('data-lang');
languageSelectorModal.style.display = 'none';
// Now open the message editor modal
if (currentCustomerIdForMessage) {
openMessageEditor(currentCustomerIdForMessage);
}
});
});
// Edit Customer Form Submit
editCustomerForm.addEventListener('submit', async function(e) {
e.preventDefault();
const customerId = parseInt(editCustomerIdInput.value);
const newName = editCustomerNameInput.value;
const newPhone = editCustomerPhoneInput.value;
const newDate = editWashDateInput.value;
const existingCustomer = await getCustomerByPhone(newPhone);
if (existingCustomer && existingCustomer.id !== customerId) {
document.getElementById('editPhoneError').style.display = 'block';
return;
}
const customerToUpdate = {
id: customerId,
name: newName,
phone: newPhone,
lastServiceDate: newDate,
createdAt: existingCustomer ? existingCustomer.createdAt : new Date().toISOString()
};
try {
await updateCustomerInDB(customerToUpdate);
showNotification(currentLanguage === 'en' ? 'Customer updated successfully!' : 'ग्राहक सफलतापूर्वक अपडेट किया गया!');
editCustomerModal.style.display = 'none';
renderCustomers();
updateStats();
renderReminders();
} catch (error) {
console.error("Failed to update customer:", error);
showNotification(currentLanguage === 'en' ? 'Failed to update customer.' : 'ग्राहक को अपडेट करने में विफल रहा।');
}
});
// Send WhatsApp message from the editor
sendWhatsAppBtn.addEventListener('click', async () => {
if (currentCustomerIdForMessage) {
const customer = await getCustomerFromDB(currentCustomerIdForMessage);
if (customer) {
const editedMessage = whatsappMessageText.value;
sendWhatsAppMessage(customer.phone, editedMessage);
messageEditorModal.style.display = 'none'; // Close the modal
}
}
});
// Download data button
downloadBtn.addEventListener('click', async function() {
const allCustomers = await getCustomersFromDB();
if (allCustomers.length === 0) {
alert(currentLanguage === 'en' ? 'No data to download.' : 'डाउनलोड करने के लिए कोई डेटा नहीं है।');
return;
}
downloadCSV(allCustomers);
});
}
// Function to download data as a CSV file
function downloadCSV(data) {
const header = ["ID", "Name", "Phone", "Last Service Date", "Created At"];
const csv = [
header.join(","),
...data.map(customer => {
return [
`"${customer.id}"`,
`"${customer.name.replace(/"/g, '""')}"`,
`"${customer.phone}"`,
`"${formatDateForCSV(customer.lastServiceDate)}"`,
`"${formatDateForCSV(customer.createdAt)}"`
].join(",");
})
].join("\n");
const blob = new Blob([`\ufeff${csv}`], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement("a");
if (link.download !== undefined) {
const url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", "salon_customers.csv");
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
showNotification(currentLanguage === 'en' ? 'Data downloaded successfully!' : 'डेटा सफलतापूर्वक डाउनलोड हो गया!');
}
}
function formatDateForCSV(dateString) {
const date = new Date(dateString);
if (isNaN(date.getTime())) {
return ''; // Return empty string for invalid dates
}
const day = date.getDate().toString().padStart(2, '0');
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const year = date.getFullYear();
return `${year}-${month}-${day}`;
}
// Get reminder status based on last service date
function getReminderStatus(lastServiceDate) {
const today = new Date();
const serviceDateObj = new Date(lastServiceDate);
const timeDiff = today.getTime() - serviceDateObj.getTime();
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
const reminderDays = shopSettings.reminderDays || 20;
if (daysDiff > reminderDays) {
return 'urgent';
} else if (daysDiff > (reminderDays - 7)) { // 13-20 days
return 'warning';
} else {
return 'normal';
}
}
// Get reminder status text
function getReminderStatusText(status) {
if (currentLanguage === 'hi') {
switch(status) {
case 'urgent': return 'जरूरी';
case 'warning': return 'चेतावनी';
case 'normal': return 'सामान्य';
default: return status;
}
} else if (currentLanguage === 'pa') {
switch(status) {
case 'urgent': return 'ਤੁਰੰਤ';
case 'warning': return 'ਚੇਤਾਵਨੀ';
case 'normal': return 'ਸਧਾਰਨ';
default: return status;
}
} else {
switch(status) {
case 'urgent': return 'Urgent';
case 'warning': return 'Warning';
case 'normal': return 'Normal';
default: return status;
}
}
}
// Render customers list
async function renderCustomers(searchTerm = '') {
const customersList = document.getElementById('customersList');
const recentServices = document.getElementById('recentServices');
const allCustomers = await getCustomersFromDB(searchTerm);
// Render all customers
if (allCustomers.length === 0) {
customersList.innerHTML = `
<div class="empty-state">
<i class="fas fa-users-slash"></i>
<p class="lang-no-customers">${searchTerm ? (translations[currentLanguage]['no-customers-found'] || 'No customers found') : translations[currentLanguage]['no-customers']}</p>
</div>
`;
} else {
customersList.innerHTML = allCustomers.map(customer => {
const status = getReminderStatus(customer.lastServiceDate);
const statusClass = `status-${status}`;
return `
<div class="customer-item" data-id="${customer.id}">
<div class="customer-info">
<h3>${customer.name}</h3>
<p>${customer.phone}</p>
<p>${translations[currentLanguage]['service-date']} ${formatDate(customer.lastServiceDate)}
<span class="reminder-status ${statusClass}">${getReminderStatusText(status)}</span>
</p>
</div>
<div class="customer-actions">
<button class="action-btn btn-call" onclick="callCustomer('${customer.phone}')">
<i class="fas fa-phone"></i>
</button>
<button class="action-btn btn-whatsapp" onclick="showLanguageSelector(${customer.id})">
<i class="fab fa-whatsapp"></i>
</button>
<button class="action-btn btn-edit" onclick="editCustomer(${customer.id})">
<i class="fas fa-edit"></i>
</button>
<button class="action-btn btn-danger" onclick="deleteCustomer(${customer.id})">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
`;
}).join('');
}
// Render recent services (last 5)
const recentCustomers = [...allCustomers]
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
.slice(0, 5);
if (recentCustomers.length === 0) {
recentServices.innerHTML = `
<div class="empty-state">
<i class="fas fa-users-slash"></i>
<p class="lang-no-customers">${translations[currentLanguage]['no-customers']}</p>
</div>
`;
} else {
recentServices.innerHTML = recentCustomers.map(customer => {
const status = getReminderStatus(customer.lastServiceDate);
const statusClass = `status-${status}`;
return `
<div class="customer-item">
<div class="customer-info">
<h3>${customer.name}</h3>
<p>${customer.phone} | ${translations[currentLanguage]['service-date']} ${formatDate(customer.lastServiceDate)}
<span class="reminder-status ${statusClass}">${getReminderStatusText(status)}</span>
</p>
</div>
<div class="customer-actions">
<button class="action-btn btn-whatsapp" onclick="showLanguageSelector(${customer.id})">
<i class="fab fa-whatsapp"></i>
</button>
</div>
</div>
`;
}).join('');
}
}
// Function to open the edit modal and populate data
window.editCustomer = async function(customerId) {
const customer = await getCustomerFromDB(customerId);
if (customer) {
editCustomerIdInput.value = customer.id;
editCustomerNameInput.value = customer.name;
editCustomerPhoneInput.value = customer.phone;
editWashDateInput.value = customer.lastServiceDate;
document.getElementById('editPhoneError').style.display = 'none';
editCustomerModal.style.display = 'flex';
}
};
// Render reminders
async function renderReminders(sortBy = 'urgency') {
const remindersList = document.getElementById('remindersList');
const now = new Date();
const reminderDays = shopSettings.reminderDays || 20;
const allCustomers = await getCustomersFromDB();
let upcomingReminders = allCustomers.filter(customer => {
const lastServiceDate = new Date(customer.lastServiceDate);
const timeDiff = now.getTime() - lastServiceDate.getTime();
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
return daysDiff >= reminderDays;
});
// Sort reminders based on selected option
if (sortBy === 'urgency') {
upcomingReminders.sort((a, b) => {
const statusA = getReminderStatus(a.lastServiceDate);
const statusB = getReminderStatus(b.lastServiceDate);
const statusOrder = { 'urgent': 0, 'warning': 1, 'normal': 2 };
return statusOrder[statusA] - statusOrder[statusB];
});
} else {
upcomingReminders.sort((a, b) => new Date(a.lastServiceDate) - new Date(b.lastServiceDate));
}
if (upcomingReminders.length === 0) {
remindersList.innerHTML = `
<div class="empty-state">
<i class="fas fa-bell-slash"></i>
<p class="lang-no-reminders">${translations[currentLanguage]['no-reminders']}</p>
</div>
`;
} else {
remindersList.innerHTML = upcomingReminders.map(customer => {
const lastServiceDate = new Date(customer.lastServiceDate);
const timeDiff = now.getTime() - lastServiceDate.getTime();
const daysSinceService = Math.ceil(timeDiff / (1000 * 3600 * 24));
const status = getReminderStatus(customer.lastServiceDate);
return `
<div class="reminder-item ${status}" data-customer-id="${customer.id}">
<h3>${customer.name}
<span class="reminder-status status-${status}">${getReminderStatusText(status)}</span>
</h3>
<p><i class="fas fa-calendar"></i> ${translations[currentLanguage]['service-date']} ${formatDate(customer.lastServiceDate)}</p>
<p><i class="fas fa-bell"></i> ${daysSinceService} ${translations[currentLanguage]['days-since-service']}</p>
<div style="display: flex; gap: 10px; margin-top: 10px;">
<button class="btn btn-whatsapp" onclick="showLanguageSelector(${customer.id})">
<i class="fab fa-whatsapp"></i> ${translations[currentLanguage]['whatsapp']}
</button>
<button class="btn btn-call" onclick="callCustomer('${customer.phone}')">
<i class="fas fa-phone"></i> ${translations[currentLanguage]['call']}
</button>
</div>
</div>
`;
}).join('');
}
// Update notification badge
document.getElementById('notificationBadge').textContent = upcomingReminders.length;
}
// Update statistics
async function updateStats() {
const allCustomers = await getCustomersFromDB();
// Total customers
document.getElementById('totalCustomers').textContent = allCustomers.length;
const now = new Date();
const reminderDays = shopSettings.reminderDays || 20;
// Count customers who need a haircut
const customersNeedingService = allCustomers.filter(customer => {
const lastServiceDate = new Date(customer.lastServiceDate);
const timeDiff = now.getTime() - lastServiceDate.getTime();
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
return daysDiff >= reminderDays;
}).length;
// Count services this month
const thisMonth = new Date().getMonth();
const thisYear = new Date().getFullYear();
const servicesThisMonth = allCustomers.filter(customer => {
const lastServiceDate = new Date(customer.lastServiceDate);
return lastServiceDate.getMonth() === thisMonth &&
lastServiceDate.getFullYear() === thisYear;
}).length;
// Update the stats
document.getElementById('upcomingReminders').textContent = customersNeedingService;
document.getElementById('servicesThisMonth').textContent = servicesThisMonth;
document.getElementById('callsToday').textContent = customersNeedingService;
}
// Format date to DD/MM/YYYY
function formatDate(dateString) {
const date = new Date(dateString);
const day = date.getDate().toString().padStart(2, '0');
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const year = date.getFullYear();
return `${day}/${month}/${year}`;
}
// Show notification
function showNotification(message) {
notificationText.textContent = message;
notification.classList.add('show');
setTimeout(() => {
notification.classList.remove('show');
}, 3000);
}
// Call customer
window.callCustomer = function(phoneNumber) {
window.open(`tel:${phoneNumber}`, '_self');
};
// Get default message based on language
function getDefaultMessage(customerName, lang) {
const reminderDays = shopSettings.reminderDays || 20;
const shopName = shopSettings.name || 'Hair Cutting Salon';
const shopPhone = shopSettings.phone ? `\n\n${translations[currentLanguage]['shop-phone']} ${shopSettings.phone}` : '';
switch(lang) {
case 'english':
return `Hello ${customerName}!\n\nIt's been ${reminderDays} days since your last hair cut with us.\n\nWe believe in not just cutting hair, but a fresh new look for your style!\n\nSpecial Offer\nGet one hair cut FREE if you get your hair cut 5 times in 6 months.\n\nVisit us today for a new look!\n\n${shopName}${shopPhone}`;
case 'hindi':
return `नमस्ते ${customerName} जी!\n\n${reminderDays} दिन पहले आपने हमारे यहाँ से हेयर कट करवाया था। अब फिर से एक नया स्टाइल देने का समय आ गया है!\n\nक्योंकि बात सिर्फ हेयर कट की नहीं, आपकी पर्सनालिटी की है!\n\nस्पेशल ऑफर\nअगर आप 6 महीने में 5 बार हेयर कट करवाते हैं, तो 1 हेयर कट बिल्कुल फ्री मिलेगा।\n\nआज ही आइए और अपनी पर्सनालिटी को दीजिए एक शानदार लुक!\n\n${shopName}${shopPhone}`;
case 'punjabi':
return `ਸਤਿ ਸ਼੍ਰੀ ਅਕਾਲ ${customerName} ਜੀ!\n\n${reminderDays} ਦਿਨ ਪਹਿਲਾਂ ਤੁਸੀਂ ਸਾਡੇ ਕੋਲੋਂ ਹੇਅਰ ਕੱਟ ਕਰਵਾਇਆ ਸੀ। ਹੁਣ ਫਿਰ ਤੋਂ ਇੱਕ ਨਵਾਂ ਸਟਾਈਲ ਦੇਣ ਦਾ ਸਮਾਂ ਆ ਗਿਆ ਹੈ!\n\nਕਿਉਂਕਿ ਗੱਲ ਸਿਰਫ ਹੇਅਰ ਕੱਟ ਦੀ ਨਹੀਂ, ਤੁਹਾਡੀ ਸ਼ਖਸੀਅਤ ਦੀ ਹੈ!\n\nਖਾਸ ਪੇਸ਼ਕਸ਼\nਜੇ ਤੁਸੀਂ 6 ਮਹੀਨਿਆਂ ਵਿੱਚ 5 ਵਾਰ ਹੇਅਰ ਕੱਟ ਕਰਵਾਉਂਦੇ ਹੋ, ਤਾਂ 1 ਵਾਰ ਬਿਲਕੁਲ ਮੁਫਤ ਕੀਤਾ ਜਾਵੇਗਾ।\n\nਅੱਜ ਹੀ ਆਓ ਅਤੇ ਆਪਣੀ ਸ਼ਖਸੀਅਤ ਨੂੰ ਇੱਕ ਸ਼ਾਨਦਾਰ ਲੁੱਕ ਦਿਓ!\n\n${shopName}${shopPhone}`;
default:
return `Hello ${customerName}!\n\nIt's been ${reminderDays} days since your last hair cut with us. It's time for a new style!\n\nVisit us today!\n\n${shopName}${shopPhone}`;
}
}
// Show language selector for WhatsApp message
window.showLanguageSelector = function(customerId) {
currentCustomerIdForMessage = customerId;
languageSelectorModal.style.display = 'flex';
};
// Open the message editor modal with pre-populated text
async function openMessageEditor(customerId) {
const customer = await getCustomerFromDB(customerId);
if (!customer) return;
const defaultMessage = getDefaultMessage(customer.name, selectedMessageLanguage);
whatsappMessageText.value = defaultMessage;
messageEditorModal.style.display = 'flex';
}
// Function to handle sending the WhatsApp message
function sendWhatsAppMessage(phoneNumber, message) {
const encodedMessage = encodeURIComponent(message);
window.open(`https://wa.me/${phoneNumber}?text=${encodedMessage}`, '_blank');
}
// Delete customer
window.deleteCustomer = async function(customerId) {
if (confirm(currentLanguage === 'en' ? 'Are you sure you want to delete this customer?' : 'क्या आप वाकई इस ग्राहक को हटाना चाहते हैं?')) {
try {
await deleteCustomerFromDB(customerId);
showNotification(currentLanguage === 'en' ? 'Customer deleted successfully!' : 'ग्राहक सफलतापूर्वक हटाया गया!');
renderCustomers();
updateStats();
renderReminders();
} catch (error) {
console.error("Failed to delete customer:", error);
showNotification(currentLanguage === 'en' ? 'Failed to delete customer.' : 'ग्राहक को हटाने में विफल रहा।');
}
}
};
initApp();
});
</script>
</body>
</html>
Comments
Post a Comment