Skip to content

Commit 2f037f7

Browse files
authored
Create cardreminder.html
1 parent 346e715 commit 2f037f7

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed

cardreminder.html

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<meta name="apple-mobile-web-app-capable" content="yes">
7+
<title>Credit Card Todo Reminder</title>
8+
<style>
9+
body {
10+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
11+
padding: 20px;
12+
max-width: 600px;
13+
margin: 0 auto;
14+
}
15+
.card-item {
16+
background: #f5f5f5;
17+
padding: 15px;
18+
margin: 10px 0;
19+
border-radius: 8px;
20+
}
21+
input, button {
22+
padding: 8px;
23+
margin: 5px 0;
24+
}
25+
button {
26+
background: #007aff;
27+
color: white;
28+
border: none;
29+
border-radius: 5px;
30+
cursor: pointer;
31+
}
32+
.export-import {
33+
margin-top: 20px;
34+
}
35+
</style>
36+
</head>
37+
<body>
38+
<h1>Credit Card Reminders</h1>
39+
40+
<div id="addForm">
41+
<input type="text" id="cardName" placeholder="Card Name">
42+
<input type="number" id="dueDate" placeholder="Due Date (1-31)" min="1" max="31">
43+
<button onclick="addCard()">Add Card</button>
44+
</div>
45+
46+
<div id="cardList"></div>
47+
48+
<div class="export-import">
49+
<button onclick="exportData()">Export Data</button>
50+
<input type="file" id="importFile" accept=".json" onchange="importData(event)">
51+
<label for="importFile">Import Data</label>
52+
</div>
53+
54+
<script>
55+
let cards = JSON.parse(localStorage.getItem('creditCards')) || [];
56+
57+
function saveCards() {
58+
localStorage.setItem('creditCards', JSON.stringify(cards));
59+
renderCards();
60+
}
61+
62+
function addCard() {
63+
const name = document.getElementById('cardName').value;
64+
const dueDate = parseInt(document.getElementById('dueDate').value);
65+
66+
if (name && dueDate >= 1 && dueDate <= 31) {
67+
cards.push({ name, dueDate });
68+
saveCards();
69+
document.getElementById('cardName').value = '';
70+
document.getElementById('dueDate').value = '';
71+
}
72+
}
73+
74+
function deleteCard(index) {
75+
cards.splice(index, 1);
76+
saveCards();
77+
}
78+
79+
function getDaysUntilDue(dueDate) {
80+
const today = new Date();
81+
const currentDay = today.getDate();
82+
const currentMonth = today.getMonth();
83+
const currentYear = today.getFullYear();
84+
85+
let nextDue = new Date(currentYear, currentMonth, dueDate);
86+
if (currentDay > dueDate) {
87+
nextDue = new Date(currentYear, currentMonth + 1, dueDate);
88+
}
89+
90+
const diffTime = nextDue - today;
91+
return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
92+
}
93+
94+
function renderCards() {
95+
const cardList = document.getElementById('cardList');
96+
cardList.innerHTML = '';
97+
98+
cards.forEach((card, index) => {
99+
const daysUntilDue = getDaysUntilDue(card.dueDate);
100+
const cardDiv = document.createElement('div');
101+
cardDiv.className = 'card-item';
102+
cardDiv.innerHTML = `
103+
<strong>${card.name}</strong><br>
104+
Due Date: ${card.dueDate}<br>
105+
Days until due: ${daysUntilDue}<br>
106+
<button onclick="deleteCard(${index})">Delete</button>
107+
`;
108+
cardList.appendChild(cardDiv);
109+
});
110+
}
111+
112+
function exportData() {
113+
const dataStr = JSON.stringify(cards);
114+
const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
115+
const exportFileDefaultName = 'credit_card_reminders.json';
116+
117+
const linkElement = document.createElement('a');
118+
linkElement.setAttribute('href', dataUri);
119+
linkElement.setAttribute('download', exportFileDefaultName);
120+
linkElement.click();
121+
}
122+
123+
function importData(event) {
124+
const file = event.target.files[0];
125+
if (file) {
126+
const reader = new FileReader();
127+
reader.onload = function(e) {
128+
try {
129+
cards = JSON.parse(e.target.result);
130+
saveCards();
131+
} catch (error) {
132+
alert('Error importing data: Invalid file format');
133+
}
134+
};
135+
reader.readAsText(file);
136+
}
137+
}
138+
139+
// Initial render
140+
renderCards();
141+
142+
// Check reminders daily
143+
setInterval(() => {
144+
cards.forEach(card => {
145+
const daysUntilDue = getDaysUntilDue(card.dueDate);
146+
if (daysUntilDue <= 3 && daysUntilDue >= 0) {
147+
if ('Notification' in window && Notification.permission === 'granted') {
148+
new Notification(`${card.name} payment due in ${daysUntilDue} day(s)!`);
149+
}
150+
}
151+
});
152+
renderCards();
153+
}, 24 * 60 * 60 * 1000); // Check every 24 hours
154+
155+
// Request notification permission
156+
if ('Notification' in window && Notification.permission !== 'denied') {
157+
Notification.requestPermission();
158+
}
159+
</script>
160+
</body>
161+
</html>

0 commit comments

Comments
 (0)