Skip to content

Instantly share code, notes, and snippets.

@sfinktah
Last active July 24, 2024 13:55
Show Gist options
  • Save sfinktah/1371ef96e460b272b1affcf35d64d415 to your computer and use it in GitHub Desktop.
Save sfinktah/1371ef96e460b272b1affcf35d64d415 to your computer and use it in GitHub Desktop.
OpenAI's idea of how to create a PWA for offline/online submission of form data

Creating a Progressive Web App (PWA) to store contact details from a form and submit them when internet access is available involves a combination of technologies like HTML, CSS, JavaScript, and service workers. Below is a simplified example of how you can achieve this:

  1. HTML Form: Create an HTML form to collect contact details. You can create an index.html file.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Contact Details Form</title>
</head>
<body>
    <h1>Contact Details</h1>
    <form id="contactForm">
        <label for="name">Name:</label>
        <input type="text" id="name" name="name" required><br>

        <label for="email">Email:</label>
        <input type="email" id="email" name="email" required><br>

        <label for="phone">Phone:</label>
        <input type="tel" id="phone" name="phone" required><br>

        <button type="submit">Submit</button>
    </form>

    <script src="app.js"></script>
</body>
</html>
  1. JavaScript: Create a JavaScript file (app.js) to handle form submission and store data locally when there's no internet access.
// Check if service workers are supported
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('service-worker.js')
        .then(function(registration) {
            console.log('Service Worker registered with scope:', registration.scope);
        })
        .catch(function(error) {
            console.error('Service Worker registration failed:', error);
        });
}

const contactForm = document.getElementById('contactForm');

contactForm.addEventListener('submit', function(event) {
    event.preventDefault();

    const name = document.getElementById('name').value;
    const email = document.getElementById('email').value;
    const phone = document.getElementById('phone').value;

    // Create a JSON object with the contact details
    const contact = {
        name,
        email,
        phone,
    };

    // Check if there's internet access
    if (navigator.onLine) {
        // If online, send data to the server
        sendDataToServer(contact);
    } else {
        // If offline, store data locally
        storeDataLocally(contact);
    }

    // Clear the form
    contactForm.reset();
});

function sendDataToServer(contact) {
    // Implement code to send data to the server using fetch or another method
    // Example: fetch('/api/contacts', { method: 'POST', body: JSON.stringify(contact) });
}

function storeDataLocally(contact) {
    // Store data locally, e.g., in IndexedDB or localStorage
    // You can use a library like Dexie.js for IndexedDB
    // Example: indexedDB.put('contacts', contact);
}
  1. Service Worker: Create a service worker (service-worker.js) to cache assets and handle offline functionality. It should be placed in the root directory of your project.
self.addEventListener('install', function(event) {
    event.waitUntil(
        caches.open('contact-app-cache').then(function(cache) {
            return cache.addAll([
                // Add the URLs of your assets to cache here
                '/',
                '/index.html',
                '/app.js',
                // Add more URLs as needed
            ]);
        })
    );
});

self.addEventListener('fetch', function(event) {
    event.respondWith(
        caches.match(event.request).then(function(response) {
            return response || fetch(event.request);
        })
    );
});
  1. Manifest File: Create a manifest.json file to specify your PWA's metadata. This file should be included in the HTML file to enable the PWA features.
{
    "name": "Contact App",
    "short_name": "Contacts",
    "description": "Store and submit contact details",
    "start_url": "/",
    "display": "standalone",
    "background_color": "#ffffff",
    "theme_color": "#000000",
    "icons": [
        {
            "src": "icon.png",
            "sizes": "192x192",
            "type": "image/png"
        }
    ]
}
  1. Icon: Create an icon (e.g., icon.png) for your PWA and place it in the root directory.

  2. Testing: Test your PWA locally and deploy it to a web server with HTTPS for a more secure experience.

This is a basic example to get you started with a PWA for storing and submitting contact details when internet access is available. Depending on your requirements, you may need to enhance error handling, implement synchronization strategies, and secure data storage.


To store data locally using IndexedDB in your Progressive Web App (PWA), you can modify the JavaScript code from the previous example. Here's how you can store contact details locally using IndexedDB:

  1. Modify the JavaScript Code (app.js):
// Check if service workers are supported
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('service-worker.js')
        .then(function(registration) {
            console.log('Service Worker registered with scope:', registration.scope);
        })
        .catch(function(error) {
            console.error('Service Worker registration failed:', error);
        });
}

const contactForm = document.getElementById('contactForm');

// Open a connection to the IndexedDB database
const request = indexedDB.open('contactsDB', 1);

request.onupgradeneeded = function(event) {
    const db = event.target.result;

    // Create an object store to store contact data
    const objectStore = db.createObjectStore('contacts', { keyPath: 'email' });

    // Create an index to query contacts by name
    objectStore.createIndex('name', 'name', { unique: false });
};

request.onerror = function(event) {
    console.error('IndexedDB error:', event.target.error);
};

request.onsuccess = function(event) {
    const db = event.target.result;

    contactForm.addEventListener('submit', function(event) {
        event.preventDefault();

        const name = document.getElementById('name').value;
        const email = document.getElementById('email').value;
        const phone = document.getElementById('phone').value;

        const contact = {
            name,
            email,
            phone,
        };

        const transaction = db.transaction(['contacts'], 'readwrite');
        const objectStore = transaction.objectStore('contacts');

        // Add the contact to the object store
        const addRequest = objectStore.add(contact);

        addRequest.onsuccess = function() {
            console.log('Contact added to IndexedDB:', contact);
        };

        addRequest.onerror = function() {
            console.error('Error adding contact to IndexedDB:', addRequest.error);
        };

        // Clear the form
        contactForm.reset();
    });
};

In this code:

  • We open a connection to an IndexedDB database called 'contactsDB'.
  • In the 'onupgradeneeded' event, we create an object store called 'contacts' to store contact data with email as the key path. We also create an index to query contacts by name.
  • In the 'onsuccess' event, we set up an event listener for the form submission. When the form is submitted, we add the contact data to the 'contacts' object store.

This code initializes and uses IndexedDB to store contact details locally in the 'contacts' object store.

Make sure to handle errors and implement retrieval and synchronization logic as needed based on your application's requirements.


To send the data stored in IndexedDB to a server when an internet connection is available, you need to implement logic that checks for internet connectivity and periodically synchronizes data between IndexedDB and your server. Here's a modification to the JavaScript code (app.js) to accomplish this:

// Check if service workers are supported
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('service-worker.js')
        .then(function(registration) {
            console.log('Service Worker registered with scope:', registration.scope);
        })
        .catch(function(error) {
            console.error('Service Worker registration failed:', error);
        });
}

const contactForm = document.getElementById('contactForm');

// Open a connection to the IndexedDB database
const request = indexedDB.open('contactsDB', 1);

request.onupgradeneeded = function(event) {
    const db = event.target.result;

    // Create an object store to store contact data
    const objectStore = db.createObjectStore('contacts', { keyPath: 'email' });

    // Create an index to query contacts by name
    objectStore.createIndex('name', 'name', { unique: false });
};

request.onerror = function(event) {
    console.error('IndexedDB error:', event.target.error);
};

request.onsuccess = function(event) {
    const db = event.target.result;

    contactForm.addEventListener('submit', function(event) {
        event.preventDefault();

        const name = document.getElementById('name').value;
        const email = document.getElementById('email').value;
        const phone = document.getElementById('phone').value;

        const contact = {
            name,
            email,
            phone,
        };

        const transaction = db.transaction(['contacts'], 'readwrite');
        const objectStore = transaction.objectStore('contacts');

        // Add the contact to the object store
        const addRequest = objectStore.add(contact);

        addRequest.onsuccess = function() {
            console.log('Contact added to IndexedDB:', contact);

            // Check for internet connectivity and synchronize
            if (navigator.onLine) {
                syncDataWithServer();
            }
        };

        addRequest.onerror = function() {
            console.error('Error adding contact to IndexedDB:', addRequest.error);
        };

        // Clear the form
        contactForm.reset();
    });
};

function syncDataWithServer() {
    const db = request.result;
    const transaction = db.transaction(['contacts'], 'readonly');
    const objectStore = transaction.objectStore('contacts');

    objectStore.getAll().onsuccess = function(event) {
        const contacts = event.target.result;

        // Send contacts to the server
        fetch('/api/sync', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(contacts),
        })
        .then(function(response) {
            if (response.ok) {
                // Data successfully synced, you may want to remove synced data from IndexedDB
                clearSyncedDataFromIndexedDB(contacts);
            } else {
                console.error('Failed to sync data:', response.status);
            }
        })
        .catch(function(error) {
            console.error('Error while syncing data:', error);
        });
    };
}

function clearSyncedDataFromIndexedDB(data) {
    const db = request.result;
    const transaction = db.transaction(['contacts'], 'readwrite');
    const objectStore = transaction.objectStore('contacts');

    data.forEach(function(contact) {
        objectStore.delete(contact.email);
    });
}

In this code:

  1. We added a syncDataWithServer function to send the data stored in IndexedDB to the server using the fetch API. Adjust the URL and request headers as needed to match your server's API.

  2. After successfully syncing the data with the server, we have a clearSyncedDataFromIndexedDB function that removes the synced data from IndexedDB. This ensures that only unsynced data remains in IndexedDB.

  3. When a new contact is added to IndexedDB, we check for internet connectivity (navigator.onLine). If there is an internet connection, we immediately attempt to sync the data with the server.

Make sure you have a server API endpoint to receive and store the data sent from the client. Additionally, you may want to implement error handling and further synchronization strategies based on your application's requirements.


To check for internet connectivity periodically every 10 minutes, you can use JavaScript's setInterval function to run a connectivity check function at regular intervals. Here's how to modify your code to achieve this:

// ...

// Check for internet connectivity every 10 minutes (600,000 milliseconds)
const checkConnectivityInterval = 600000;

// Function to check internet connectivity
function checkConnectivity() {
    if (navigator.onLine) {
        syncDataWithServer(); // If online, try to sync data with the server
    }
}

// Set up the periodic connectivity check
setInterval(checkConnectivity, checkConnectivityInterval);

// ...

In this code:

  1. We define the checkConnectivity function that checks for internet connectivity (navigator.onLine) and, if online, calls the syncDataWithServer function to attempt data synchronization.

  2. We set the checkConnectivityInterval to 600,000 milliseconds (10 minutes).

  3. We use setInterval to repeatedly call the checkConnectivity function at the specified interval, which will check for connectivity every 10 minutes.

With this modification, your application will periodically check for internet connectivity and attempt to sync data with the server when an internet connection is available. Adjust the checkConnectivityInterval value to suit your specific requirements.


You would insert the code for checking internet connectivity every 10 minutes in your existing JavaScript file (app.js) where you've set up the IndexedDB and handling of form submissions. Here's where you would insert the code:

// ...

// Open a connection to the IndexedDB database
const request = indexedDB.open('contactsDB', 1);

request.onupgradeneeded = function(event) {
    const db = event.target.result;

    // Create an object store to store contact data
    const objectStore = db.createObjectStore('contacts', { keyPath: 'email' });

    // Create an index to query contacts by name
    objectStore.createIndex('name', 'name', { unique: false });
};

request.onerror = function(event) {
    console.error('IndexedDB error:', event.target.error);
};

request.onsuccess = function(event) {
    const db = event.target.result;

    contactForm.addEventListener('submit', function(event) {
        event.preventDefault();

        const name = document.getElementById('name').value;
        const email = document.getElementById('email').value;
        const phone = document.getElementById('phone').value;

        const contact = {
            name,
            email,
            phone,
        };

        const transaction = db.transaction(['contacts'], 'readwrite');
        const objectStore = transaction.objectStore('contacts');

        // Add the contact to the object store
        const addRequest = objectStore.add(contact);

        addRequest.onsuccess = function() {
            console.log('Contact added to IndexedDB:', contact);

            // Check for internet connectivity and synchronize
            if (navigator.onLine) {
                syncDataWithServer();
            }
        };

        addRequest.onerror = function() {
            console.error('Error adding contact to IndexedDB:', addRequest.error);
        };

        // Clear the form
        contactForm.reset();
    });

    // Check for internet connectivity every 10 minutes (600,000 milliseconds)
    const checkConnectivityInterval = 600000;

    // Function to check internet connectivity
    function checkConnectivity() {
        if (navigator.onLine) {
            syncDataWithServer(); // If online, try to sync data with the server
        }
    }

    // Set up the periodic connectivity check
    setInterval(checkConnectivity, checkConnectivityInterval);
};

// ...

You can insert this code block after the request.onsuccess event handler where you've been handling form submissions and data synchronization. This code will periodically check for internet connectivity and attempt to sync data with the server every 10 minutes while your PWA is running. Adjust the interval (checkConnectivityInterval) as needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment