Skip to content

glennmccaus/Medical

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 

Repository files navigation

Medical

Family Medical App and medication and appointment reminders

<title>Family Medical Survival System</title>
<!-- PWA Configuration -->
<meta name="theme-color" content="#667eea">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Family Medical">
<meta name="mobile-web-app-capable" content="yes">

<!-- PWA Manifest -->
<link rel="manifest" id="pwa-manifest">

<!-- QR Code Library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>

<style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }

    body {
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        min-height: 100vh;
        color: #333;
        line-height: 1.6;
    }

    .container {
        max-width: 1400px;
        margin: 0 auto;
        padding: 20px;
    }

    .header {
        text-align: center;
        color: white;
        margin-bottom: 30px;
        padding: 30px 0;
    }

    .header h1 {
        font-size: 2.5rem;
        font-weight: 300;
        margin-bottom: 10px;
        text-shadow: 0 2px 4px rgba(0,0,0,0.3);
    }

    .login-section {
        background: rgba(255,255,255,0.1);
        backdrop-filter: blur(10px);
        border-radius: 15px;
        padding: 25px;
        margin-bottom: 30px;
        color: white;
        text-align: center;
    }

    .family-member-list {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
        gap: 15px;
        margin: 20px 0;
    }

    .member-card {
        padding: 20px;
        background: rgba(255,255,255,0.2);
        border: none;
        border-radius: 15px;
        color: white;
        font-size: 1.1rem;
        font-weight: 600;
        cursor: pointer;
        transition: all 0.3s ease;
        backdrop-filter: blur(10px);
        text-align: left;
    }

    .member-card:hover {
        background: rgba(255,255,255,0.3);
        transform: translateY(-2px);
    }

    .member-card.active {
        background: rgba(255,255,255,0.4);
        border: 2px solid white;
    }

    .member-card.new-member {
        border: 2px dashed rgba(255,255,255,0.6);
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 100px;
    }

    .add-member-btn {
        background: rgba(46, 204, 113, 0.8);
        border: none;
        color: white;
        padding: 15px 30px;
        border-radius: 25px;
        font-size: 1rem;
        font-weight: bold;
        cursor: pointer;
        margin: 10px;
        transition: all 0.3s ease;
    }

    .add-member-btn:hover {
        background: rgba(46, 204, 113, 1);
        transform: translateY(-2px);
    }

    .privacy-controls {
        background: rgba(255,255,255,0.1);
        backdrop-filter: blur(10px);
        border-radius: 15px;
        padding: 20px;
        margin-bottom: 30px;
        color: white;
    }

    .privacy-toggle {
        display: flex;
        align-items: center;
        margin: 10px 0;
        padding: 10px;
        background: rgba(255,255,255,0.1);
        border-radius: 10px;
    }

    .toggle-switch {
        position: relative;
        width: 60px;
        height: 30px;
        background: rgba(255,255,255,0.3);
        border-radius: 15px;
        margin-right: 15px;
        cursor: pointer;
        transition: all 0.3s ease;
    }

    .toggle-switch.active {
        background: #2ecc71;
    }

    .toggle-slider {
        position: absolute;
        top: 3px;
        left: 3px;
        width: 24px;
        height: 24px;
        background: white;
        border-radius: 50%;
        transition: all 0.3s ease;
    }

    .toggle-switch.active .toggle-slider {
        transform: translateX(30px);
    }

    .system-status {
        background: rgba(255,255,255,0.1);
        backdrop-filter: blur(10px);
        border-radius: 15px;
        padding: 20px;
        margin-bottom: 30px;
        color: white;
        text-align: center;
    }

    .status-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
        gap: 15px;
        margin-top: 15px;
    }

    .status-item {
        background: rgba(255,255,255,0.2);
        padding: 15px;
        border-radius: 10px;
        text-align: center;
    }

    .status-online {
        color: #4CAF50;
    }

    .main-content {
        background: rgba(255,255,255,0.95);
        backdrop-filter: blur(20px);
        border-radius: 20px;
        padding: 30px;
        margin-bottom: 30px;
        box-shadow: 0 15px 35px rgba(0,0,0,0.1);
    }

    .profile-header {
        display: flex;
        align-items: center;
        margin-bottom: 30px;
        padding-bottom: 20px;
        border-bottom: 2px solid #eee;
    }

    .profile-icon {
        font-size: 3rem;
        margin-right: 20px;
    }

    .profile-info h2 {
        color: #2c3e50;
        margin-bottom: 5px;
    }

    .profile-status {
        color: #7f8c8d;
        font-size: 0.9rem;
    }

    .info-sections {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
        gap: 25px;
    }

    .info-section {
        background: #f8f9fa;
        padding: 20px;
        border-radius: 15px;
        border-left: 4px solid #3498db;
    }

    .section-title {
        font-size: 1.2rem;
        font-weight: 600;
        color: #2c3e50;
        margin-bottom: 15px;
        display: flex;
        align-items: center;
    }

    .section-icon {
        margin-right: 10px;
        font-size: 1.5rem;
    }

    .info-item {
        margin-bottom: 10px;
        padding: 10px;
        background: white;
        border-radius: 8px;
        border-left: 3px solid #ecf0f1;
    }

    .info-label {
        font-weight: 600;
        color: #34495e;
        margin-bottom: 5px;
    }

    .info-value {
        color: #7f8c8d;
    }

    .action-buttons {
        display: flex;
        flex-wrap: wrap;
        gap: 15px;
        margin-top: 30px;
        padding-top: 20px;
        border-top: 2px solid #eee;
    }

    .action-button {
        padding: 12px 24px;
        background: linear-gradient(45deg, #3498db, #2980b9);
        color: white;
        border: none;
        border-radius: 25px;
        font-weight: 600;
        cursor: pointer;
        transition: all 0.3s ease;
        box-shadow: 0 5px 15px rgba(52, 152, 219, 0.4);
    }

    .action-button:hover {
        transform: translateY(-2px);
        box-shadow: 0 8px 25px rgba(52, 152, 219, 0.6);
    }

    .action-button.emergency {
        background: linear-gradient(45deg, #e74c3c, #c0392b);
        box-shadow: 0 5px 15px rgba(231, 76, 60, 0.4);
    }

    .action-button.success {
        background: linear-gradient(45deg, #27ae60, #229954);
        box-shadow: 0 5px 15px rgba(39, 174, 96, 0.4);
    }

    .modal {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0,0,0,0.7);
        z-index: 2000;
        justify-content: center;
        align-items: center;
    }

    .modal-content {
        background: white;
        border-radius: 20px;
        padding: 30px;
        max-width: 600px;
        width: 90%;
        max-height: 90vh;
        overflow-y: auto;
    }

    .form-group {
        margin-bottom: 20px;
    }

    .form-label {
        display: block;
        margin-bottom: 8px;
        font-weight: 600;
        color: #2c3e50;
    }

    .form-input, .form-textarea, .form-select {
        width: 100%;
        padding: 12px;
        border: 2px solid #ecf0f1;
        border-radius: 8px;
        font-size: 1rem;
        transition: border-color 0.3s ease;
    }

    .form-input:focus, .form-textarea:focus, .form-select:focus {
        outline: none;
        border-color: #3498db;
    }

    .form-textarea {
        resize: vertical;
        min-height: 80px;
    }

    .notification {
        position: fixed;
        top: 20px;
        right: 20px;
        background: white;
        padding: 20px;
        border-radius: 10px;
        box-shadow: 0 10px 30px rgba(0,0,0,0.3);
        z-index: 3000;
        max-width: 350px;
        transform: translateX(400px);
        transition: all 0.3s ease;
    }

    .notification.show {
        transform: translateX(0);
    }

    .notification.success {
        border-left: 4px solid #27ae60;
    }

    .notification.error {
        border-left: 4px solid #e74c3c;
    }

    .notification.info {
        border-left: 4px solid #3498db;
    }

    .welcome-screen {
        text-align: center;
        padding: 50px 20px;
        color: #7f8c8d;
    }

    .welcome-icon {
        font-size: 4rem;
        margin-bottom: 20px;
    }

    @media (max-width: 768px) {
        .container { padding: 15px; }
        .header h1 { font-size: 2rem; }
        .info-sections { grid-template-columns: 1fr; }
        .family-member-list { grid-template-columns: 1fr; }
        .action-buttons { flex-direction: column; }
    }
</style>
πŸ₯

Family Medical Survival System

Private Family Health Management
    <!-- Login Section -->
    <div class="login-section" id="login-section">
        <h3>πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦ Select Your Profile</h3>
        <div class="family-member-list" id="family-member-list">
            <!-- Family members will be populated here -->
        </div>
        <button class="add-member-btn" onclick="showAddMemberModal()">βž• Add New Family Member</button>
        
        <div style="margin-top: 20px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,0.3);">
            <h4>πŸ”’ Privacy Settings</h4>
            <div class="privacy-controls">
                <div class="privacy-toggle">
                    <div class="toggle-switch" id="appointments-privacy" onclick="togglePrivacy('appointments')">
                        <div class="toggle-slider"></div>
                    </div>
                    <label>Share appointments with family</label>
                </div>
                <div class="privacy-toggle">
                    <div class="toggle-switch" id="medications-privacy" onclick="togglePrivacy('medications')">
                        <div class="toggle-slider"></div>
                    </div>
                    <label>Share medication reminders</label>
                </div>
                <div class="privacy-toggle">
                    <div class="toggle-switch active" id="emergency-privacy" onclick="togglePrivacy('emergency')">
                        <div class="toggle-slider"></div>
                    </div>
                    <label>Emergency contact sharing (always on)</label>
                </div>
            </div>
        </div>
    </div>

    <!-- System Status -->
    <div class="system-status">
        <h3>πŸ”„ System Status</h3>
        <div class="status-grid">
            <div class="status-item">
                <div class="status-online">●</div>
                <div>Family System Online</div>
            </div>
            <div class="status-item">
                <div id="member-count">πŸ‘₯ 0 Members</div>
            </div>
            <div class="status-item">
                <div>πŸ” Privacy Protected</div>
            </div>
            <div class="status-item">
                <div>πŸ“± Mobile Ready</div>
            </div>
        </div>
    </div>

    <!-- Main Content Area -->
    <div class="main-content" id="main-content" style="display: none;">
        <!-- Profile content will be loaded here -->
    </div>

    <!-- Welcome Screen -->
    <div class="welcome-screen" id="welcome-screen">
        <div class="welcome-icon">πŸ‘‹</div>
        <h2>Welcome to Your Family Medical System</h2>
        <p>Select a family member above to view their medical information, or add a new member to get started.</p>
        <p style="margin-top: 20px; font-size: 0.9rem; opacity: 0.8;">
            πŸ”’ All information is kept private and only visible to the individual unless they choose to share specific details.
        </p>
    </div>
</div>

<!-- Add Member Modal -->
<div id="add-member-modal" class="modal">
    <div class="modal-content">
        <h2>βž• Add New Family Member</h2>
        
        <div class="form-group">
            <label class="form-label">πŸ‘€ Name:</label>
            <input type="text" id="new-member-name" class="form-input" placeholder="Enter name">
        </div>
        
        <div class="form-group">
            <label class="form-label">🎭 Role:</label>
            <select id="new-member-role" class="form-select">
                <option value="">Select role...</option>
                <option value="parent">πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦ Parent</option>
                <option value="child">πŸ‘§πŸ‘¦ Child</option>
                <option value="grandparent">πŸ‘΄πŸ‘΅ Grandparent</option>
                <option value="sibling">πŸ‘« Sibling</option>
                <option value="spouse">πŸ’‘ Spouse/Partner</option>
                <option value="other">πŸ‘€ Other Family</option>
            </select>
        </div>
        
        <div class="form-group">
            <label class="form-label">πŸ“§ Email (for login):</label>
            <input type="email" id="new-member-email" class="form-input" placeholder="email@example.com">
        </div>
        
        <div class="action-buttons">
            <button class="action-button success" onclick="addFamilyMember()">βœ… Add Member</button>
            <button class="action-button" onclick="closeAddMemberModal()">❌ Cancel</button>
        </div>
    </div>
</div>

<!-- Edit Profile Modal -->
<div id="edit-profile-modal" class="modal">
    <div class="modal-content">
        <h2 id="edit-profile-title">✏️ Edit Profile</h2>
        
        <div class="form-group">
            <label class="form-label">πŸ‘€ Name:</label>
            <input type="text" id="edit-name" class="form-input">
        </div>
        
        <div class="form-group">
            <label class="form-label">πŸ₯ Medical Conditions:</label>
            <textarea id="edit-conditions" class="form-textarea" placeholder="List any medical conditions..."></textarea>
        </div>
        
        <div class="form-group">
            <label class="form-label">⚠️ Allergies:</label>
            <input type="text" id="edit-allergies" class="form-input" placeholder="e.g., Penicillin, Nuts, or 'None Known'">
        </div>
        
        <div class="form-group">
            <label class="form-label">πŸ’Š Current Medications:</label>
            <textarea id="edit-medications" class="form-textarea" placeholder="List medications, dosage, and timing..."></textarea>
        </div>
        
        <div class="form-group">
            <label class="form-label">πŸ‘¨β€βš•οΈ Primary Doctor:</label>
            <input type="text" id="edit-doctor" class="form-input" placeholder="Dr. Name - Phone Number">
        </div>
        
        <div class="form-group">
            <label class="form-label">πŸ“ž Emergency Contact:</label>
            <input type="text" id="edit-emergency" class="form-input" placeholder="Name - Phone Number">
        </div>
        
        <div class="form-group">
            <label class="form-label">🩸 Blood Type:</label>
            <select id="edit-bloodtype" class="form-select">
                <option value="">Unknown</option>
                <option value="A+">A+</option>
                <option value="A-">A-</option>
                <option value="B+">B+</option>
                <option value="B-">B-</option>
                <option value="AB+">AB+</option>
                <option value="AB-">AB-</option>
                <option value="O+">O+</option>
                <option value="O-">O-</option>
            </select>
        </div>
        
        <div class="form-group">
            <label class="form-label">πŸ“… Upcoming Appointments:</label>
            <textarea id="edit-appointments" class="form-textarea" placeholder="List upcoming appointments..."></textarea>
        </div>
        
        <div class="action-buttons">
            <button class="action-button success" onclick="saveProfile()">πŸ’Ύ Save Changes</button>
            <button class="action-button" onclick="closeEditProfileModal()">❌ Cancel</button>
            <button class="action-button emergency" onclick="deleteMember()">πŸ—‘οΈ Remove Member</button>
        </div>
    </div>
</div>

<!-- QR Code Modal -->
<div id="qr-modal" class="modal">
    <div class="modal-content" style="text-align: center;">
        <h2 id="qr-title">πŸ“± Emergency QR Code</h2>
        <div id="qr-code" style="margin: 20px 0;"></div>
        <p id="qr-instructions">Show this QR code to emergency responders</p>
        <div class="action-buttons" style="justify-content: center;">
            <button class="action-button" onclick="closeQRModal()">Close</button>
        </div>
    </div>
</div>

<script>
    // Family data structure - using memory storage for this environment
    let familyData = {};
    let currentUser = null;
    let privacySettings = {
        appointments: false,
        medications: false,
        emergency: true
    };

    // Initialize the application
    function init() {
        loadFamilyData();
        updateMemberList();
        updatePrivacyToggles();
        showNotification('Family Medical System ready!', 'success');
    }

    // Family member management
    function loadFamilyData() {
        // In a real app, this would load from secure storage
        if (Object.keys(familyData).length === 0) {
            // Add sample data for demonstration
            familyData['sample-member'] = {
                id: 'sample-member',
                name: 'Sample Member',
                role: 'parent',
                email: 'sample@family.com',
                conditions: '',
                allergies: '',
                medications: '',
                doctor: '',
                emergency: '',
                bloodType: '',
                appointments: '',
                lastLogin: new Date().toISOString()
            };
        }
    }

    function saveFamilyData() {
        // In a real app, this would save to secure storage
        console.log('Family data saved to memory');
    }

    function updateMemberList() {
        const memberList = document.getElementById('family-member-list');
        memberList.innerHTML = '';

        Object.values(familyData).forEach(member => {
            const memberCard = document.createElement('div');
            memberCard.className = 'member-card';
            memberCard.onclick = () => selectMember(member.id);
            
            const roleIcon = getRoleIcon(member.role);
            const lastSeen = member.lastLogin ? new Date(member.lastLogin).toLocaleDateString() : 'Never';
            
            memberCard.innerHTML = `
                <div style="font-size: 1.5rem; margin-bottom: 5px;">${roleIcon}</div>
                <div style="font-weight: bold;">${member.name}</div>
                <div style="font-size: 0.8rem; opacity: 0.8;">${member.role}</div>
                <div style="font-size: 0.7rem; opacity: 0.6;">Last active: ${lastSeen}</div>
            `;
            
            memberList.appendChild(memberCard);
        });

        // Update member count
        document.getElementById('member-count').textContent = `πŸ‘₯ ${Object.keys(familyData).length} Members`;
    }

    function getRoleIcon(role) {
        const icons = {
            'parent': 'πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦',
            'child': 'πŸ‘§',
            'grandparent': 'πŸ‘΄',
            'sibling': 'πŸ‘«',
            'spouse': 'πŸ’‘',
            'other': 'πŸ‘€'
        };
        return icons[role] || 'πŸ‘€';
    }

    function selectMember(memberId) {
        currentUser = memberId;
        const member = familyData[memberId];
        
        if (!member) {
            showNotification('Member not found', 'error');
            return;
        }

        // Update last login
        member.lastLogin = new Date().toISOString();
        saveFamilyData();

        // Hide login section and welcome screen
        document.getElementById('login-section').style.display = 'none';
        document.getElementById('welcome-screen').style.display = 'none';
        document.getElementById('main-content').style.display = 'block';

        // Load member profile
        loadMemberProfile(member);
        
        // Update member list to show active state
        document.querySelectorAll('.member-card').forEach(card => {
            card.classList.remove('active');
        });
        event.target.closest('.member-card').classList.add('active');

        showNotification(`Welcome back, ${member.name}!`, 'success');
    }

    function loadMemberProfile(member) {
        const mainContent = document.getElementById('main-content');
        const roleIcon = getRoleIcon(member.role);
        
        mainContent.innerHTML = `
            <div class="profile-header">
                <div class="profile-icon">${roleIcon}</div>
                <div class="profile-info">
                    <h2>${member.name}</h2>
                    <div class="profile-status">Family ${member.role} β€’ Last updated: ${new Date(member.lastLogin).toLocaleDateString()}</div>
                </div>
            </div>

            <div class="info-sections">
                <div class="info-section">
                    <div class="section-title">
                        <span class="section-icon">πŸ₯</span>
                        Medical Information
                    </div>
                    <div class="info-item">
                        <div class="info-label">Conditions</div>
                        <div class="info-value">${member.conditions || 'None specified'}</div>
                    </div>
                    <div class="info-item">
                        <div class="info-label">Allergies</div>
                        <div class="info-value">${member.allergies || 'None known'}</div>
                    </div>
                    <div class="info-item">
                        <div class="info-label">Blood Type</div>
                        <div class="info-value">${member.bloodType || 'Unknown'}</div>
                    </div>
                </div>

                <div class="info-section">
                    <div class="section-title">
                        <span class="section-icon">πŸ’Š</span>
                        Medications
                    </div>
                    <div class="info-item">
                        <div class="info-label">Current Medications</div>
                        <div class="info-value">${member.medications || 'None specified'}</div>
                    </div>
                </div>

                <div class="info-section">
                    <div class="section-title">
                        <span class="section-icon">πŸ‘¨β€βš•οΈ</span>
                        Healthcare Team
                    </div>
                    <div class="info-item">
                        <div class="info-label">Primary Doctor</div>
                        <div class="info-value">${member.doctor || 'Not specified'}</div>
                    </div>
                    <div class="info-item">
                        <div class="info-label">Emergency Contact</div>
                        <div class="info-value">${member.emergency || 'Not specified'}</div>
                    </div>
                </div>

                <div class="info-section">
                    <div class="section-title">
                        <span class="section-icon">πŸ“…</span>
                        Appointments
                    </div>
                    <div class="info-item">
                        <div class="info-label">Upcoming</div>
                        <div class="info-value">${member.appointments || 'No appointments scheduled'}</div>
                    </div>
                </div>
            </div>

            <div class="action-buttons">
                <button class="action-button" onclick="editProfile()">✏️ Edit My Information</button>
                <button class="action-button emergency" onclick="generateEmergencyQR()">πŸ“± Emergency QR Code</button>
                <button class="action-button" onclick="logOut()">πŸšͺ Switch User</button>
            </div>
        `;
    }

    // Member management functions
    function showAddMemberModal() {
        document.getElementById('add-member-modal').style.display = 'flex';
    }

    function closeAddMemberModal() {
        document.getElementById('add-member-modal').style.display = 'none';
        clearAddMemberForm();
    }

    function clearAddMemberForm() {
        document.getElementById('new-member-name').value = '';
        document.getElementById('new-member-role').value = '';
        document.getElementById('new-member-email').value = '';
    }

    function addFamilyMember() {
        const name = document.getElementById('new-member-name').value.trim();
        const role = document.getElementById('new-member-role').value;
        const email = document.getElementById('new-member-email').value.trim();

        if (!name || !role || !email) {
            showNotification('Please fill in all fields', 'error');
            return;
        }

        // Generate unique ID
        const memberId = 'member-' + Date.now();

        // Create new member
        familyData[memberId] = {
            id: memberId,
            name: name,
            role: role,
            email: email,
            conditions: '',
            allergies: '',
            medications: '',
            doctor: '',
            emergency: '',
            bloodType: '',
            appointments: '',
            lastLogin: new Date().toISOString()
        };

        saveFamilyData();
        updateMemberList();
        closeAddMemberModal();
        showNotification(`${name} added to family!`, 'success');
    }

    function editProfile() {
        if (!currentUser) return;
        
        const member = familyData[currentUser];
        document.getElementById('edit-profile-title').textContent = `Edit ${member.name}'s Profile`;
        
        // Pre-fill form
        document.getElementById('edit-name').value = member.name || '';
        document.getElementById('edit-conditions').value = member.conditions || '';
        document.getElementById('edit-allergies').value = member.allergies || '';
        document.getElementById('edit-medications').value = member.medications || '';
        document.getElementById('edit-doctor').value = member.doctor || '';
        document.getElementById('edit-emergency').value = member.emergency || '';
        document.getElementById('edit-bloodtype').value = member.bloodType || '';
        document.getElementById('edit-appointments').value = member.appointments || '';
        
        document.getElementById('edit-profile-modal').style.display = 'flex';
    }

    function closeEditProfileModal() {
        document.getElementById('edit-profile-modal').style.display = 'none';
    }

    function saveProfile() {
        if (!currentUser) return;
        
        const member = familyData[currentUser];
        
        // Update member data
        member.name = document.getElementById('edit-name').value.trim();
        member.conditions = document.getElementById('edit-conditions').value.trim();
        member.allergies = document.getElementById('edit-allergies').value.trim();
        member.medications = document.getElementById('edit-medications').value.trim();
        member.doctor = document.getElementById('edit-doctor').value.trim();
        member.emergency = document.getElementById('edit-emergency').value.trim();
        member.bloodType = document.getElementById('edit-bloodtype').value;
        member.appointments = document.getElementById('edit-appointments').value.trim();
        member.lastLogin = new Date().toISOString();
        
        saveFamilyData();
        loadMemberProfile(member);
        updateMemberList();
        closeEditProfileModal();
        showNotification('Profile updated successfully!', 'success');
    }

    function deleteMember() {
        if (!currentUser) return;
        
        const member = familyData[currentUser];
        const confirmDelete = confirm(`Are you sure you want to remove ${member.name} from the family system? This cannot be undone.`);
        
        if (confirmDelete) {
            delete familyData[currentUser];
            saveFamilyData();
            updateMemberList();
            logOut();
            showNotification(`${member.name} removed from family system`, 'info');
        }
    }

    function logOut() {
        currentUser = null;
        document.getElementById('login-section').style.display = 'block';
        document.getElementById('main-content').style.display = 'none';
        document.getElementById('welcome-screen').style.display = 'block';
        
        // Remove active states
        document.querySelectorAll('.member-card').forEach(card => {
            card.classList.remove('active');
        });
        
        closeEditProfileModal();
        closeQRModal();
    }

    // Privacy controls
    function updatePrivacyToggles() {
        Object.keys(privacySettings).forEach(setting => {
            const toggle = document.getElementById(`${setting}-privacy`);
            if (toggle) {
                if (privacySettings[setting]) {
                    toggle.classList.add('active');
                } else {
                    toggle.classList.remove('active');
                }
            }
        });
    }

    function togglePrivacy(setting) {
        if (setting === 'emergency') {
            showNotification('Emergency sharing cannot be disabled for safety', 'info');
            return;
        }
        
        privacySettings[setting] = !privacySettings[setting];
        updatePrivacyToggles();
        
        const status = privacySettings[setting] ? 'enabled' : 'disabled';
        showNotification(`${setting} sharing ${status}`, 'info');
    }

    // QR Code generation
    function generateEmergencyQR() {
        if (!currentUser) return;
        
        const member = familyData[currentUser];
        
        // Prepare emergency data
        const emergencyInfo = {
            name: member.name,
            role: member.role,
            conditions: member.conditions || 'Not specified',
            allergies: member.allergies || 'Not specified',
            medications: member.medications || 'Not specified',
            doctor: member.doctor || 'Not specified',
            emergency_contact: member.emergency || 'Not specified',
            blood_type: member.bloodType || 'Unknown',
            generated: new Date().toISOString()
        };
        
        const qrData = `EMERGENCY MEDICAL INFO

Name: ${emergencyInfo.name} Role: ${emergencyInfo.role} Conditions: ${emergencyInfo.conditions} Allergies: ${emergencyInfo.allergies} Medications: ${emergencyInfo.medications} Doctor: ${emergencyInfo.doctor} Emergency Contact: ${emergencyInfo.emergency_contact} Blood Type: ${emergencyInfo.blood_type} Generated: ${new Date().toLocaleString()}`;

        // Clear previous QR code
        const qrContainer = document.getElementById('qr-code');
        qrContainer.innerHTML = '';
        
        // Check if QRCode library is available
        if (typeof QRCode === 'undefined') {
            showNotification('QR Code library not available', 'error');
            return;
        }
        
        try {
            new QRCode(qrContainer, {
                text: qrData,
                width: 256,
                height: 256,
                colorDark: '#000000',
                colorLight: '#ffffff',
                correctLevel: QRCode.CorrectLevel.M
            });
            
            document.getElementById('qr-title').textContent = `Emergency QR Code for ${member.name}`;
            document.getElementById('qr-instructions').textContent = 'Show this QR code to emergency responders for instant access to medical information';
            document.getElementById('qr-modal').style.display = 'flex';
            
            showNotification('Emergency QR code generated', 'success');
        } catch (error) {
            showNotification('Error generating QR code', 'error');
            console.error('QR Code generation error:', error);
        }
    }

    function closeQRModal() {
        document.getElementById('qr-modal').style.display = 'none';
    }

    // Notification system
    function showNotification(message, type = 'info') {
        // Remove existing notifications
        document.querySelectorAll('.notification').forEach(notification => {
            notification.remove();
        });
        
        const notification = document.createElement('div');
        notification.className = `notification ${type} show`;
        
        const icons = {
            success: 'βœ…',
            error: '❌',
            info: 'ℹ️',
            warning: '⚠️'
        };
        
        notification.innerHTML = `
            <div style="font-weight: bold; margin-bottom: 8px;">
                ${icons[type] || icons.info} ${type.charAt(0).toUpperCase() + type.slice(1)}
            </div>
            <div>${message}</div>
        `;
        
        document.body.appendChild(notification);
        
        // Auto-remove after 4 seconds
        setTimeout(() => {
            notification.classList.remove('show');
            setTimeout(() => {
                if (document.body.contains(notification)) {
                    document.body.removeChild(notification);
                }
            }, 300);
        }, 4000);
    }

    // Modal management
    function closeModalOnOutsideClick(event) {
        if (event.target.classList.contains('modal')) {
            event.target.style.display = 'none';
        }
    }

    // Keyboard shortcuts
    function handleKeyboardShortcuts(event) {
        if (event.key === 'Escape') {
            closeEditProfileModal();
            closeAddMemberModal();
            closeQRModal();
        }
    }

    // Family sharing functions
    function getSharedAppointments() {
        if (!privacySettings.appointments) return {};
        
        const shared = {};
        Object.values(familyData).forEach(member => {
            if (member.appointments) {
                shared[member.name] = member.appointments;
            }
        });
        return shared;
    }

    function getSharedMedications() {
        if (!privacySettings.medications) return {};
        
        const shared = {};
        Object.values(familyData).forEach(member => {
            if (member.medications) {
                shared[member.name] = member.medications;
            }
        });
        return shared;
    }

    function getFamilyEmergencyContacts() {
        const contacts = {};
        Object.values(familyData).forEach(member => {
            if (member.emergency) {
                contacts[member.name] = member.emergency;
            }
        });
        return contacts;
    }

    // Search and filter functions
    function searchFamily(query) {
        const results = [];
        const searchTerm = query.toLowerCase();
        
        Object.values(familyData).forEach(member => {
            if (member.name.toLowerCase().includes(searchTerm) ||
                member.role.toLowerCase().includes(searchTerm) ||
                member.conditions.toLowerCase().includes(searchTerm)) {
                results.push(member);
            }
        });
        
        return results;
    }

    // Data export/import functions
    function exportFamilyData() {
        const exportData = {
            familyData: familyData,
            privacySettings: privacySettings,
            exportDate: new Date().toISOString(),
            version: '2.0'
        };
        
        const dataStr = JSON.stringify(exportData, null, 2);
        const dataBlob = new Blob([dataStr], {type: 'application/json'});
        
        const link = document.createElement('a');
        link.href = URL.createObjectURL(dataBlob);
        link.download = `family-medical-data-${new Date().toISOString().split('T')[0]}.json`;
        link.click();
        
        showNotification('Family data exported successfully', 'success');
    }

    function importFamilyData(fileInput) {
        const file = fileInput.files[0];
        if (!file) return;
        
        const reader = new FileReader();
        reader.onload = function(e) {
            try {
                const importData = JSON.parse(e.target.result);
                
                if (importData.familyData) {
                    familyData = importData.familyData;
                }
                if (importData.privacySettings) {
                    privacySettings = importData.privacySettings;
                }
                
                saveFamilyData();
                updateMemberList();
                updatePrivacyToggles();
                
                showNotification('Family data imported successfully', 'success');
            } catch (error) {
                showNotification('Error importing data: Invalid file format', 'error');
            }
        };
        reader.readAsText(file);
    }

    // Emergency functions
    function triggerFamilyEmergency() {
        const emergencyContacts = getFamilyEmergencyContacts();
        
        showNotification('Emergency alert sent to all family members', 'error');
        
        // In a real app, this would send notifications to all family members
        console.log('Emergency contacts:', emergencyContacts);
    }

    function checkMedicationReminders() {
        const now = new Date();
        const reminders = [];
        
        Object.values(familyData).forEach(member => {
            if (member.medications && privacySettings.medications) {
                // Parse medication times and check for reminders
                // This is a simplified version - real app would have proper scheduling
                reminders.push(`${member.name}: Check medications`);
            }
        });
        
        return reminders;
    }

    // Event listeners
    // Note: PWA initialization moved to bottom of file
    document.addEventListener('click', closeModalOnOutsideClick);
    document.addEventListener('keydown', handleKeyboardShortcuts);

    // Periodic updates
    setInterval(() => {
        const reminders = checkMedicationReminders();
        if (reminders.length > 0 && currentUser) {
            // Show medication reminders
            console.log('Medication reminders:', reminders);
        }
    }, 60000); // Check every minute

    // PWA support - only enable when served from a server
    if ('serviceWorker' in navigator && window.location.protocol !== 'file:') {
        window.addEventListener('load', () => {
            // Register service worker inline
            const swCode = `
                const CACHE_NAME = 'family-medical-v1';
                const urlsToCache = [
                    '/',
                    'https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js'
                ];

                self.addEventListener('install', function(event) {
                    event.waitUntil(
                        caches.open(CACHE_NAME).then(function(cache) {
                            return cache.addAll(urlsToCache);
                        })
                    );
                });

                self.addEventListener('fetch', function(event) {
                    event.respondWith(
                        caches.match(event.request).then(function(response) {
                            return response || fetch(event.request);
                        })
                    );
                });
            `;
            
            const blob = new Blob([swCode], { type: 'application/javascript' });
            const swUrl = URL.createObjectURL(blob);
            
            navigator.serviceWorker.register(swUrl)
                .then(registration => {
                    console.log('PWA Service Worker registered successfully');
                    showNotification('App ready for offline use!', 'success');
                })
                .catch(error => {
                    console.log('Service Worker registration failed:', error);
                });
        });
    }

    // Create PWA manifest dynamically
    function createPWAManifest() {
        const manifest = {
            "name": "Family Medical Survival System",
            "short_name": "FamilyMed",
            "description": "Private family medical management system",
            "start_url": window.location.pathname,
            "display": "standalone",
            "background_color": "#667eea",
            "theme_color": "#667eea",
            "icons": [
                {
                    "src": "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3EπŸ₯%3C/text%3E%3C/svg%3E",
                    "sizes": "192x192",
                    "type": "image/svg+xml"
                },
                {
                    "src": "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3EπŸ₯%3C/text%3E%3C/svg%3E",
                    "sizes": "512x512",
                    "type": "image/svg+xml"
                }
            ],
            "categories": ["medical", "health", "family"],
            "lang": "en"
        };
        
        const manifestBlob = new Blob([JSON.stringify(manifest)], { type: 'application/json' });
        const manifestUrl = URL.createObjectURL(manifestBlob);
        document.getElementById('pwa-manifest').href = manifestUrl;
    }

    // Initialize PWA
    document.addEventListener('DOMContentLoaded', function() {
        createPWAManifest();
        init();
    });

    // Auto-save functionality
    let autoSaveTimeout;
    function scheduleAutoSave() {
        clearTimeout(autoSaveTimeout);
        autoSaveTimeout = setTimeout(() => {
            saveFamilyData();
            console.log('Auto-saved family data');
        }, 5000);
    }

    // Add auto-save to input events
    document.addEventListener('input', scheduleAutoSave);
</script>

About

Family Medical App and medication and appointment reminders

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors