| File | Date | Name | Due | Paid | Balance | Status | By |
|---|---|---|---|---|---|---|---|
📋 No data yet. | |||||||
| File | Date | Name | Due | Paid | Balance | Status | By | Del |
|---|---|---|---|---|---|---|---|---|
🔎 Connect your Sheet and refresh. | ||||||||
⚠️ Security note: Credentials are stored in localStorage and your Google Sheet. Suitable for a small trusted team. For sensitive data, consider a proper backend auth system.
Step 1 — Create your Google Sheet
Go to sheets.google.com, create a spreadsheet named LoanTrack. Rename Sheet1 to Repayments, add a second sheet named Users.
Repayments headers (Row 1):
File Number | Date | Name | Amount Due | Amount Paid | Balance | Entered By | Timestamp
Users headers (Row 1):
username | password | role
Add your team in rows below. Roles: admin or staff.
Step 2 — Apps Script
Go to Extensions → Apps Script, delete existing code, paste:
const SS = SpreadsheetApp.getActiveSpreadsheet();
function doGet(e) {
const action = e.parameter.action;
if (action === 'login') {
const rows = SS.getSheetByName('Users').getDataRange().getValues().slice(1);
const user = rows.find(r =>
String(r[0]).toLowerCase() === String(e.parameter.username).toLowerCase() &&
String(r[1]) === String(e.parameter.password)
);
return user
? json({ status:'ok', role:user[2], username:user[0] })
: json({ status:'error', message:'Invalid credentials' });
}
if (action === 'getRecords') {
const sh = SS.getSheetByName('Repayments');
const data = sh.getDataRange().getValues();
const headers = data[0];
const rows = data.slice(1).filter(r => r[0] !== '').map(r => {
const obj = {};
headers.forEach((h,i) => obj[h] = r[i]);
return obj;
});
return json({ status:'ok', data:rows });
}
if (action === 'getUsers') {
const rows = SS.getSheetByName('Users').getDataRange().getValues().slice(1)
.filter(r => r[0]).map(r => ({ username:r[0], role:r[2] }));
return json({ status:'ok', users:rows });
}
return json({ status:'error', message:'Unknown action' });
}
function doPost(e) {
const p = JSON.parse(e.postData.contents);
if (p.action === 'append') {
SS.getSheetByName('Repayments').appendRow([
p.fileNo, p.date, p.name,
p.amountDue, p.amountPaid, p.balance,
p.enteredBy, new Date().toISOString()
]);
return json({ status:'ok' });
}
if (p.action === 'deleteRow') {
const sh = SS.getSheetByName('Repayments');
const data = sh.getDataRange().getValues();
for (let i = data.length - 1; i >= 1; i--) {
if (String(data[i][0])===String(p.fileNo) &&
String(data[i][1])===String(p.date) &&
String(data[i][2])===String(p.name)) {
sh.deleteRow(i + 1);
return json({ status:'ok' });
}
}
return json({ status:'error', message:'Row not found' });
}
if (p.action === 'addUser') {
SS.getSheetByName('Users').appendRow([p.username, p.password, p.role]);
return json({ status:'ok' });
}
return json({ status:'error', message:'Unknown action' });
}
function json(obj) {
return ContentService.createTextOutput(JSON.stringify(obj))
.setMimeType(ContentService.MimeType.JSON);
}Step 3 — Deploy
Step 4 — Connect & Deploy to Azure
On the login screen click "Configure Google Sheet connection" and paste the URL. Then drop loan-app.html into your Azure Static Web App. Done.