Skip to content

Instantly share code, notes, and snippets.

@isaacssemugenyi
Created January 8, 2026 04:59
Show Gist options
  • Select an option

  • Save isaacssemugenyi/b8f4a3ef98edcd2358ac79db28de4fde to your computer and use it in GitHub Desktop.

Select an option

Save isaacssemugenyi/b8f4a3ef98edcd2358ac79db28de4fde to your computer and use it in GitHub Desktop.
// Existing global state (KEEP)
let contacts = [];
let lastId = 0;
/**
* NEW: AddressBook class
* We introduce it but DO NOT break existing code
*/
class AddressBook {
constructor(store, clock = () => new Date().toISOString()) {
this.store = store;
this.clock = clock;
}
/**
* REFACTORED METHOD
* - Cleaner validation
* - Single responsibility
* - No behavior change
*/
addContact(name, phone, email, address) {
if (!name || !phone) {
return false;
}
const existing = this.store.find(c => c.phone === phone);
if (existing) {
return false;
}
lastId = lastId + 1;
const contact = {
id: lastId,
name: name.trim(),
phone: phone.trim(),
email: email ? email.trim() : "",
address: address ? address.trim() : "",
createdAt: this.clock()
};
this.store.push(contact);
return true;
}
}
// Create ONE shared instance
const addressBook = new AddressBook(contacts);
/**
* 🔁 BACKWARD-COMPATIBLE FUNCTION
* Tests still call this — so we keep it
*/
function addContact(name, phone, email, address) {
return addressBook.addContact(name, phone, email, address);
}
/*
function addContact(name, phone, email, address) {
if (name == null || name === "") {
console.log("Name is required");
return false;
}
if (phone == null || phone === "") {
console.log("Phone is required");
return false;
}
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
console.log("Phone already exists");
return false;
}
}
lastId = lastId + 1;
let contact = {
id: lastId,
name: name,
phone: phone,
email: email ? email : "",
address: address ? address : "",
createdAt: new Date().toISOString()
};
contacts.push(contact);
console.log("Contact added:", contact.name);
return true;
} */
function getAllContacts() {
if (contacts.length === 0) {
console.log("No contacts found");
return [];
}
let result = [];
for (let i = 0; i < contacts.length; i++) {
result.push(contacts[i]);
}
return result;
}
function findContactByPhone(phone) {
if (!phone) {
console.log("Phone required");
return null;
}
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
return contacts[i];
}
}
return null;
}
function updateContact(phone, newName, newEmail, newAddress) {
let found = false;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
if (newName) {
contacts[i].name = newName;
}
if (newEmail) {
contacts[i].email = newEmail;
}
if (newAddress) {
contacts[i].address = newAddress;
}
contacts[i].updatedAt = new Date().toISOString();
console.log("Contact updated");
found = true;
}
}
if (!found) {
console.log("Contact not found");
return false;
}
return true;
}
function deleteContact(phone) {
let index = -1;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
index = i;
}
}
if (index === -1) {
console.log("Contact not found");
return false;
}
contacts.splice(index, 1);
console.log("Contact deleted");
return true;
}
function searchContacts(keyword) {
let results = [];
if (!keyword) {
return results;
}
for (let i = 0; i < contacts.length; i++) {
if (
contacts[i].name.includes(keyword) ||
contacts[i].phone.includes(keyword) ||
contacts[i].email.includes(keyword)
) {
results.push(contacts[i]);
}
}
return results;
}
/*************
* Demo usage
*************/
if (require.main === module) {
addContact('John Doe', '0700000001', 'john@email.com', 'Kampala');
addContact("Jane Smith", "0700000002", "", "");
updateContact("0700000001", "John D.", null, "Ntinda");
console.log(getAllContacts());
console.log(findContactByPhone("0700000002"));
console.log(searchContacts("John"));
}
module.exports = {
addContact,
getAllContacts,
findContactByPhone,
updateContact,
deleteContact,
searchContacts
}
// Existing global state (KEEP)
let contacts = [];
let lastId = 0;
/**
* NEW: AddressBook class
* We introduce it but DO NOT break existing code
*/
class AddressBook {
constructor(store, clock = () => new Date().toISOString()) {
this.store = store;
this.clock = clock;
}
/**
* REFACTORED METHOD
* - Cleaner validation
* - Single responsibility
* - No behavior change
*/
addContact(name, phone, email, address) {
if (!name || !phone) {
return false;
}
const existing = this.store.find(c => c.phone === phone);
if (existing) {
return false;
}
lastId = lastId + 1;
const contact = {
id: lastId,
name: name.trim(),
phone: phone.trim(),
email: email ? email.trim() : "",
address: address ? address.trim() : "",
createdAt: this.clock()
};
this.store.push(contact);
return true;
}
getAllContacts() {
if (this.store.length === 0) {
console.log("No contacts found");
return [];
}
return this.store;
}
}
// Create ONE shared instance
const addressBook = new AddressBook(contacts);
/**
* 🔁 BACKWARD-COMPATIBLE FUNCTION
* Tests still call this — so we keep it
*/
function addContact(name, phone, email, address) {
return addressBook.addContact(name, phone, email, address);
}
/* function getAllContacts() {
if (contacts.length === 0) {
console.log("No contacts found");
return [];
}
let result = [];
for (let i = 0; i < contacts.length; i++) {
result.push(contacts[i]);
}
return result;
} */
function getAllContacts(){
return addressBook.getAllContacts();
}
function findContactByPhone(phone) {
if (!phone) {
console.log("Phone required");
return null;
}
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
return contacts[i];
}
}
return null;
}
function updateContact(phone, newName, newEmail, newAddress) {
let found = false;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
if (newName) {
contacts[i].name = newName;
}
if (newEmail) {
contacts[i].email = newEmail;
}
if (newAddress) {
contacts[i].address = newAddress;
}
contacts[i].updatedAt = new Date().toISOString();
console.log("Contact updated");
found = true;
}
}
if (!found) {
console.log("Contact not found");
return false;
}
return true;
}
function deleteContact(phone) {
let index = -1;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
index = i;
}
}
if (index === -1) {
console.log("Contact not found");
return false;
}
contacts.splice(index, 1);
console.log("Contact deleted");
return true;
}
function searchContacts(keyword) {
let results = [];
if (!keyword) {
return results;
}
for (let i = 0; i < contacts.length; i++) {
if (
contacts[i].name.includes(keyword) ||
contacts[i].phone.includes(keyword) ||
contacts[i].email.includes(keyword)
) {
results.push(contacts[i]);
}
}
return results;
}
/*************
* Demo usage
*************/
if (require.main === module) {
addContact('John Doe', '0700000001', 'john@email.com', 'Kampala');
addContact("Jane Smith", "0700000002", "", "");
updateContact("0700000001", "John D.", null, "Ntinda");
console.log(getAllContacts());
console.log(findContactByPhone("0700000002"));
console.log(searchContacts("John"));
}
module.exports = {
addContact,
getAllContacts,
findContactByPhone,
updateContact,
deleteContact,
searchContacts
}
// Existing global state (KEEP)
let contacts = [];
let lastId = 0;
/**
* NEW: AddressBook class
* We introduce it but DO NOT break existing code
*/
class AddressBook {
constructor(store, clock = () => new Date().toISOString()) {
this.store = store;
this.clock = clock;
}
/**
* REFACTORED METHOD
* - Cleaner validation
* - Single responsibility
* - No behavior change
*/
addContact(name, phone, email, address) {
if (!name || !phone) {
return false;
}
const existing = this.store.find(c => c.phone === phone);
if (existing) {
return false;
}
lastId = lastId + 1;
const contact = {
id: lastId,
name: name.trim(),
phone: phone.trim(),
email: email ? email.trim() : "",
address: address ? address.trim() : "",
createdAt: this.clock()
};
this.store.push(contact);
return true;
}
getAllContacts() {
return [...this.store];
}
findContactByPhone(phone) {
if (!phone) return null;
return this.store.find(c => c.phone === phone) || null;
}
}
// Create ONE shared instance
const addressBook = new AddressBook(contacts);
/**
* 🔁 BACKWARD-COMPATIBLE FUNCTION
* Tests still call this — so we keep it
*/
function addContact(name, phone, email, address) {
return addressBook.addContact(name, phone, email, address);
}
function getAllContacts() {
return addressBook.getAllContacts();
}
/*
function findContactByPhone(phone) {
if (!phone) {
console.log("Phone required");
return null;
}
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
return contacts[i];
}
}
return null;
}*/
function findContactByPhone(phone){
return addressBook.findContactByPhone(phone);
}
function updateContact(phone, newName, newEmail, newAddress) {
let found = false;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
if (newName) {
contacts[i].name = newName;
}
if (newEmail) {
contacts[i].email = newEmail;
}
if (newAddress) {
contacts[i].address = newAddress;
}
contacts[i].updatedAt = new Date().toISOString();
console.log("Contact updated");
found = true;
}
}
if (!found) {
console.log("Contact not found");
return false;
}
return true;
}
function deleteContact(phone) {
let index = -1;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
index = i;
}
}
if (index === -1) {
console.log("Contact not found");
return false;
}
contacts.splice(index, 1);
console.log("Contact deleted");
return true;
}
function searchContacts(keyword) {
let results = [];
if (!keyword) {
return results;
}
for (let i = 0; i < contacts.length; i++) {
if (
contacts[i].name.includes(keyword) ||
contacts[i].phone.includes(keyword) ||
contacts[i].email.includes(keyword)
) {
results.push(contacts[i]);
}
}
return results;
}
/*************
* Demo usage
*************/
if (require.main === module) {
addContact('John Doe', '0700000001', 'john@email.com', 'Kampala');
addContact("Jane Smith", "0700000002", "", "");
updateContact("0700000001", "John D.", null, "Ntinda");
console.log(getAllContacts());
console.log(findContactByPhone("0700000002"));
console.log(searchContacts("John"));
}
module.exports = {
addContact,
getAllContacts,
findContactByPhone,
updateContact,
deleteContact,
searchContacts
}
// Existing global state (KEEP)
let contacts = [];
let lastId = 0;
/**
* NEW: AddressBook class
* We introduce it but DO NOT break existing code
*/
class AddressBook {
constructor(store, clock = () => new Date().toISOString()) {
this.store = store;
this.clock = clock;
}
/**
* REFACTORED METHOD
* - Cleaner validation
* - Single responsibility
* - No behavior change
*/
addContact(name, phone, email, address) {
if (!name || !phone) {
return false;
}
const existing = this.store.find(c => c.phone === phone);
if (existing) {
return false;
}
lastId = lastId + 1;
const contact = {
id: lastId,
name: name.trim(),
phone: phone.trim(),
email: email ? email.trim() : "",
address: address ? address.trim() : "",
createdAt: this.clock()
};
this.store.push(contact);
return true;
}
getAllContacts() {
return [...this.store];
}
findContactByPhone(phone) {
if (!phone) return null;
return this.store.find(c => c.phone === phone) || null;
}
updateContact(phone, newName, newEmail, newAddress) {
const contact = this.findContactByPhone(phone);
if (!contact) return false;
if (newName) contact.name = newName;
if (newEmail) contact.email = newEmail;
if (newAddress) contact.address = newAddress;
contact.updatedAt = this.clock();
return true;
}
}
// Create ONE shared instance
const addressBook = new AddressBook(contacts);
/**
* 🔁 BACKWARD-COMPATIBLE FUNCTION
* Tests still call this — so we keep it
*/
function addContact(name, phone, email, address) {
return addressBook.addContact(name, phone, email, address);
}
function getAllContacts() {
return addressBook.getAllContacts();
}
function findContactByPhone(phone) {
return addressBook.findContactByPhone(phone);
}
/*
function updateContact(phone, newName, newEmail, newAddress) {
let found = false;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
if (newName) {
contacts[i].name = newName;
}
if (newEmail) {
contacts[i].email = newEmail;
}
if (newAddress) {
contacts[i].address = newAddress;
}
contacts[i].updatedAt = new Date().toISOString();
console.log("Contact updated");
found = true;
}
}
if (!found) {
console.log("Contact not found");
return false;
}
return true;
} */
function updateContact(phone, newName, newEmail, newAddress) {
return addressBook.updateContact(phone, newName, newEmail, newAddress)
}
function deleteContact(phone) {
let index = -1;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
index = i;
}
}
if (index === -1) {
console.log("Contact not found");
return false;
}
contacts.splice(index, 1);
console.log("Contact deleted");
return true;
}
function searchContacts(keyword) {
let results = [];
if (!keyword) {
return results;
}
for (let i = 0; i < contacts.length; i++) {
if (
contacts[i].name.includes(keyword) ||
contacts[i].phone.includes(keyword) ||
contacts[i].email.includes(keyword)
) {
results.push(contacts[i]);
}
}
return results;
}
/*************
* Demo usage
*************/
if (require.main === module) {
addContact('John Doe', '0700000001', 'john@email.com', 'Kampala');
addContact("Jane Smith", "0700000002", "", "");
updateContact("0700000001", "John D.", null, "Ntinda");
console.log(getAllContacts());
console.log(findContactByPhone("0700000002"));
console.log(searchContacts("John"));
}
module.exports = {
addContact,
getAllContacts,
findContactByPhone,
updateContact,
deleteContact,
searchContacts
}
// Existing global state (KEEP)
let contacts = [];
let lastId = 0;
/**
* NEW: AddressBook class
* We introduce it but DO NOT break existing code
*/
class AddressBook {
constructor(store, clock = () => new Date().toISOString()) {
this.store = store;
this.clock = clock;
}
/**
* REFACTORED METHOD
* - Cleaner validation
* - Single responsibility
* - No behavior change
*/
addContact(name, phone, email, address) {
if (!name || !phone) {
return false;
}
const existing = this.store.find(c => c.phone === phone);
if (existing) {
return false;
}
lastId = lastId + 1;
const contact = {
id: lastId,
name: name.trim(),
phone: phone.trim(),
email: email ? email.trim() : "",
address: address ? address.trim() : "",
createdAt: this.clock()
};
this.store.push(contact);
return true;
}
getAllContacts() {
return [...this.store];
}
findContactByPhone(phone) {
if (!phone) return null;
return this.store.find(c => c.phone === phone) || null;
}
updateContact(phone, newName, newEmail, newAddress) {
const contact = this.findContactByPhone(phone);
if (!contact) return false;
if (newName) contact.name = newName;
if (newEmail) contact.email = newEmail;
if (newAddress) contact.address = newAddress;
contact.updatedAt = this.clock();
return true;
}
deleteContact(phone) {
const index = this.store.findIndex(c => c.phone === phone);
if (index === -1) return false;
this.store.splice(index, 1);
return true;
}
}
// Create ONE shared instance
const addressBook = new AddressBook(contacts);
/**
* 🔁 BACKWARD-COMPATIBLE FUNCTION
* Tests still call this — so we keep it
*/
function addContact(name, phone, email, address) {
return addressBook.addContact(name, phone, email, address);
}
function getAllContacts() {
return addressBook.getAllContacts();
}
function findContactByPhone(phone) {
return addressBook.findContactByPhone(phone);
}
function updateContact(phone, newName, newEmail, newAddress) {
return addressBook.updateContact(phone, newName, newEmail, newAddress)
}
/*
function deleteContact(phone) {
let index = -1;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
index = i;
}
}
if (index === -1) {
console.log("Contact not found");
return false;
}
contacts.splice(index, 1);
console.log("Contact deleted");
return true;
} */
function deleteContact(phone){
return addressBook.deleteContact(phone);
}
function searchContacts(keyword) {
let results = [];
if (!keyword) {
return results;
}
for (let i = 0; i < contacts.length; i++) {
if (
contacts[i].name.includes(keyword) ||
contacts[i].phone.includes(keyword) ||
contacts[i].email.includes(keyword)
) {
results.push(contacts[i]);
}
}
return results;
}
/*************
* Demo usage
*************/
if (require.main === module) {
addContact('John Doe', '0700000001', 'john@email.com', 'Kampala');
addContact("Jane Smith", "0700000002", "", "");
updateContact("0700000001", "John D.", null, "Ntinda");
console.log(getAllContacts());
console.log(findContactByPhone("0700000002"));
console.log(searchContacts("John"));
}
module.exports = {
addContact,
getAllContacts,
findContactByPhone,
updateContact,
deleteContact,
searchContacts
}
// Existing global state (KEEP)
let contacts = [];
let lastId = 0;
/**
* NEW: AddressBook class
* We introduce it but DO NOT break existing code
*/
class AddressBook {
constructor(store, clock = () => new Date().toISOString()) {
this.store = store;
this.clock = clock;
}
/**
* REFACTORED METHOD
* - Cleaner validation
* - Single responsibility
* - No behavior change
*/
addContact(name, phone, email, address) {
if (!name || !phone) {
return false;
}
const existing = this.store.find(c => c.phone === phone);
if (existing) {
return false;
}
lastId = lastId + 1;
const contact = {
id: lastId,
name: name.trim(),
phone: phone.trim(),
email: email ? email.trim() : "",
address: address ? address.trim() : "",
createdAt: this.clock()
};
this.store.push(contact);
return true;
}
getAllContacts() {
return [...this.store];
}
findContactByPhone(phone) {
if (!phone) return null;
return this.store.find(c => c.phone === phone) || null;
}
updateContact(phone, newName, newEmail, newAddress) {
const contact = this.findContactByPhone(phone);
if (!contact) return false;
if (newName) contact.name = newName;
if (newEmail) contact.email = newEmail;
if (newAddress) contact.address = newAddress;
contact.updatedAt = this.clock();
return true;
}
deleteContact(phone) {
const index = this.store.findIndex(c => c.phone === phone);
if (index === -1) return false;
this.store.splice(index, 1);
return true;
}
searchContacts(keyword) {
if (!keyword) return [];
return this.store.filter(c =>
c.name.includes(keyword) ||
c.phone.includes(keyword) ||
c.email.includes(keyword)
);
}
}
// Create ONE shared instance
const addressBook = new AddressBook(contacts);
/**
* 🔁 BACKWARD-COMPATIBLE FUNCTION
* Tests still call this — so we keep it
*/
function addContact(name, phone, email, address) {
return addressBook.addContact(name, phone, email, address);
}
function getAllContacts() {
return addressBook.getAllContacts();
}
function findContactByPhone(phone) {
return addressBook.findContactByPhone(phone);
}
function updateContact(phone, newName, newEmail, newAddress) {
return addressBook.updateContact(phone, newName, newEmail, newAddress)
}
function deleteContact(phone) {
return addressBook.deleteContact(phone);
}
/*
function searchContacts(keyword) {
let results = [];
if (!keyword) {
return results;
}
for (let i = 0; i < contacts.length; i++) {
if (
contacts[i].name.includes(keyword) ||
contacts[i].phone.includes(keyword) ||
contacts[i].email.includes(keyword)
) {
results.push(contacts[i]);
}
}
return results;
} */
function searchContacts(keyword) {
return addressBook.searchContacts(keyword);
}
/*************
* Demo usage
*************/
if (require.main === module) {
addContact('John Doe', '0700000001', 'john@email.com', 'Kampala');
addContact("Jane Smith", "0700000002", "", "");
updateContact("0700000001", "John D.", null, "Ntinda");
console.log(getAllContacts());
console.log(findContactByPhone("0700000002"));
console.log(searchContacts("John"));
}
module.exports = {
addContact,
getAllContacts,
findContactByPhone,
updateContact,
deleteContact,
searchContacts
}
// Existing global state (KEEP)
let contacts = [];
let lastId = 0;
/**
* NEW: AddressBook class
* We introduce it but DO NOT break existing code
*/
class AddressBook {
constructor(store, clock = () => new Date().toISOString()) {
this.store = store;
this.clock = clock;
}
/**
* REFACTORED METHOD
* - Cleaner validation
* - Single responsibility
* - No behavior change
*/
addContact(name, phone, email, address) {
if (!name || !phone) {
return false;
}
const existing = this.store.find(c => c.phone === phone);
if (existing) {
return false;
}
lastId = lastId + 1;
const contact = {
id: lastId,
name: name.trim(),
phone: phone.trim(),
email: email ? email.trim() : "",
address: address ? address.trim() : "",
createdAt: this.clock()
};
this.store.push(contact);
return true;
}
getAllContacts() {
return [...this.store];
}
findContactByPhone(phone) {
if (!phone) return null;
return this.store.find(c => c.phone === phone) || null;
}
updateContact(phone, newName, newEmail, newAddress) {
const contact = this.findContactByPhone(phone);
if (!contact) return false;
if (newName) contact.name = newName;
if (newEmail) contact.email = newEmail;
if (newAddress) contact.address = newAddress;
contact.updatedAt = this.clock();
return true;
}
deleteContact(phone) {
const index = this.store.findIndex(c => c.phone === phone);
if (index === -1) return false;
this.store.splice(index, 1);
return true;
}
searchContacts(keyword) {
if (!keyword) return [];
return this.store.filter(c =>
c.name.includes(keyword) ||
c.phone.includes(keyword) ||
c.email.includes(keyword)
);
}
}
// Create ONE shared instance
const addressBook = new AddressBook(contacts);
module.exports = {
addContact: (...args) => addressBook.addContact(...args),
getAllContacts: () => addressBook.getAllContacts(),
findContactByPhone: phone => addressBook.findContactByPhone(phone),
updateContact: (...args) => addressBook.updateContact(...args),
deleteContact: phone => addressBook.deleteContact(phone),
searchContacts: keyword => addressBook.searchContacts(keyword)
}
// Existing global state (KEEP)
// let contacts = [];
// let lastId = 0;
/**
* NEW: AddressBook class
* We introduce it but DO NOT break existing code
*/
class AddressBook {
constructor(clock = () => new Date().toISOString()) {
this.store = [];
this.lastId = 0;
this.clock = clock;
}
/**
* REFACTORED METHOD
* - Cleaner validation
* - Single responsibility
* - No behavior change
*/
addContact(name, phone, email, address) {
if (!name || !phone) {
return false;
}
const existing = this.store.find(c => c.phone === phone);
if (existing) {
return false;
}
this.lastId++;
const contact = {
id: this.lastId,
name: name.trim(),
phone: phone.trim(),
email: email ? email.trim() : "",
address: address ? address.trim() : "",
createdAt: this.clock()
};
this.store.push(contact);
return true;
}
getAllContacts() {
return [...this.store];
}
findContactByPhone(phone) {
if (!phone) return null;
return this.store.find(c => c.phone === phone) || null;
}
updateContact(phone, newName, newEmail, newAddress) {
const contact = this.findContactByPhone(phone);
if (!contact) return false;
if (newName) contact.name = newName;
if (newEmail) contact.email = newEmail;
if (newAddress) contact.address = newAddress;
contact.updatedAt = this.clock();
return true;
}
deleteContact(phone) {
const index = this.store.findIndex(c => c.phone === phone);
if (index === -1) return false;
this.store.splice(index, 1);
return true;
}
searchContacts(keyword) {
if (!keyword) return [];
return this.store.filter(c =>
c.name.includes(keyword) ||
c.phone.includes(keyword) ||
c.email.includes(keyword)
);
}
}
// Create ONE shared instance
const addressBook = new AddressBook();
module.exports = {
addContact: (...args) => addressBook.addContact(...args),
getAllContacts: () => addressBook.getAllContacts(),
findContactByPhone: phone => addressBook.findContactByPhone(phone),
updateContact: (...args) => addressBook.updateContact(...args),
deleteContact: phone => addressBook.deleteContact(phone),
searchContacts: keyword => addressBook.searchContacts(keyword)
}
/**************************************
* ADDRESS BOOK (REFACTORED VERSION)
* Behavior preserved, design improved
**************************************/
class AddressBook {
constructor(clock = () => new Date().toISOString()) {
this.contacts = [];
this.lastId = 0;
this.clock = clock;
}
addContact(name, phone, email, address) {
if (!name) return false;
if (!phone) return false;
if (this.contacts.some(c => c.phone === phone)) {
return false;
}
this.lastId++;
this.contacts.push({
id: this.lastId,
name,
phone,
email: email || "",
address: address || "",
createdAt: this.clock()
});
return true;
}
getAllContacts() {
return [...this.contacts];
}
findContactByPhone(phone) {
if (!phone) return null;
return this.contacts.find(c => c.phone === phone) || null;
}
updateContact(phone, newName, newEmail, newAddress) {
const contact = this.findContactByPhone(phone);
if (!contact) return false;
if (newName) contact.name = newName;
if (newEmail) contact.email = newEmail;
if (newAddress) contact.address = newAddress;
contact.updatedAt = this.clock();
return true;
}
deleteContact(phone) {
const index = this.contacts.findIndex(c => c.phone === phone);
if (index === -1) return false;
this.contacts.splice(index, 1);
return true;
}
searchContacts(keyword) {
if (!keyword) return [];
return this.contacts.filter(c =>
c.name.includes(keyword) ||
c.phone.includes(keyword) ||
c.email.includes(keyword)
);
}
}
/* ---------- Backward-compatible API ---------- */
const addressBook = new AddressBook();
module.exports = {
addContact: (...args) => addressBook.addContact(...args),
getAllContacts: () => addressBook.getAllContacts(),
findContactByPhone: phone => addressBook.findContactByPhone(phone),
updateContact: (...args) => addressBook.updateContact(...args),
deleteContact: phone => addressBook.deleteContact(phone),
searchContacts: keyword => addressBook.searchContacts(keyword)
};
/**************************************
* ADDRESS BOOK (LEGACY / MESSY VERSION)
**************************************/
let contacts = [];
let lastId = 0;
function addContact(name, phone, email, address) {
if (name == null || name === "") {
console.log("Name is required");
return false;
}
if (phone == null || phone === "") {
console.log("Phone is required");
return false;
}
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
console.log("Phone already exists");
return false;
}
}
lastId = lastId + 1;
let contact = {
id: lastId,
name: name,
phone: phone,
email: email ? email : "",
address: address ? address : "",
createdAt: new Date().toISOString()
};
contacts.push(contact);
console.log("Contact added:", contact.name);
return true;
}
function getAllContacts() {
if (contacts.length === 0) {
console.log("No contacts found");
return [];
}
let result = [];
for (let i = 0; i < contacts.length; i++) {
result.push(contacts[i]);
}
return result;
}
function findContactByPhone(phone) {
if (!phone) {
console.log("Phone required");
return null;
}
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
return contacts[i];
}
}
return null;
}
function updateContact(phone, newName, newEmail, newAddress) {
let found = false;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
if (newName) {
contacts[i].name = newName;
}
if (newEmail) {
contacts[i].email = newEmail;
}
if (newAddress) {
contacts[i].address = newAddress;
}
contacts[i].updatedAt = new Date().toISOString();
console.log("Contact updated");
found = true;
}
}
if (!found) {
console.log("Contact not found");
return false;
}
return true;
}
function deleteContact(phone) {
let index = -1;
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].phone === phone) {
index = i;
}
}
if (index === -1) {
console.log("Contact not found");
return false;
}
contacts.splice(index, 1);
console.log("Contact deleted");
return true;
}
function searchContacts(keyword) {
let results = [];
if (!keyword) {
return results;
}
for (let i = 0; i < contacts.length; i++) {
if (
contacts[i].name.includes(keyword) ||
contacts[i].phone.includes(keyword) ||
contacts[i].email.includes(keyword)
) {
results.push(contacts[i]);
}
}
return results;
}
/*************
* Demo usage
*************/
if (require.main === module) {
addContact('John Doe', '0700000001', 'john@email.com', 'Kampala');
addContact("Jane Smith", "0700000002", "", "");
updateContact("0700000001", "John D.", null, "Ntinda");
console.log(getAllContacts());
console.log(findContactByPhone("0700000002"));
console.log(searchContacts("John"));
}
module.exports = {
addContact,
getAllContacts,
findContactByPhone,
updateContact,
deleteContact,
searchContacts
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment