import {
deleteUserAccount,
getSessionUser,
updatePassword,
updateUsername
} from "./api/auth.js"
import {
addUserProfileLinks,
removeProfileLink,
updateCoverImage,
updateProfileImage,
updateUserDetails,
updateSocialLinks
} from "./api/profile.js"
import app, {
showToast
} from "./app.js"
import store from "./store.js"
var $ = Dom7
// --------------- Edit Profile Page ---------------
$(document).on(\'page:init\', \'.page[data-name="profile-edit-mydetails"]\', async function (e) {
var view = app.views.current
const user = await getSessionUser()
if (!user) {
view.router.navigate(\'/login\')
return
}
// Example of how to fill in the form fields with the provided data
document.querySelector(\'input[name="email"]\').value = user.email || \'\';
document.querySelector(\'input[name="first_name"]\').value = user.first_name || \'\';
document.querySelector(\'input[name="last_name"]\').value = user.last_name || \'\';
document.querySelector(\'input[name="tel_no"]\').value = user.billing_info?.phone || \'\';
})
$(document).on(\'click\', \'#save-details\', async function () {
var view = app.views.current
const user = await getSessionUser()
// Get the values from the input fields
const firstName = $(\'input[name="first_name"]\').val().trim();
const lastName = $(\'input[name="last_name"]\').val().trim();
const email = $(\'input[name="email"]\').val().trim();
const telNo = $(\'input[name="tel_no"]\').val().trim();
const address = $(\'textarea[name="address"]\').val().trim();
const city = $(\'input[name="city"]\').val().trim();
const provincy = $(\'input[name="provincy"]\').val().trim();
const post_code = $(\'input[name="post_code"]\').val().trim();
// Validate the input fields
if (firstName === \'\') {
showToast(\'Please enter your first name\', \'Error\');
return;
}
if (lastName === \'\') {
showToast(\'Please enter your last name\', \'Error\');
return;
}
if (email === \'\') {
showToast(\'Please enter your email\', \'Error\');
return;
}
// Simple email validation
const emailPattern = /^[^s@]+@[^s@]+.[^s@]+$/;
if (!emailPattern.test(email)) {
showToast(\'Please enter a valid email address\', \'Error\');
return;
}
// // phone validation
// if (telNo === \'\') {
// showToast(\'Please enter a valid phone number\', \'Error\');
// return
// }
// Prepare the data for the API request
const requestData = {
first_name: firstName,
last_name: lastName,
email: email,
phone: telNo,
address: address,
city: city,
provincy: provincy,
post_code: post_code,
};
// check if the request data is the same as userdata
let dirtied = false;
for (const key in requestData) {
if (key == \'phone\') {
if (requestData[key] !== user.billing_info.phone) {
dirtied = true
break;
}
continue
}
if (requestData[key] !== user[key]) {
dirtied = true
break;
}
}
if (!dirtied) {
return
}
try {
app.preloader.show()
const response = await updateUserDetails(requestData, email !== user.email)
app.preloader.hide()
if (response && response.success) {
// showToast(\'Details updated successfully\', \'Success\');
showToast(\'Details updated successfully\')
view.router.navigate(\'/profile/\')
store.dispatch(\'updateUserDetails\')
return;
}
throw new Error(response.message);
} catch (error) {
app.preloader.hide()
app.notification.create({
titleRightText: \'now\',
subtitle: \'Oops, something went wrong\',
text: error.message || \'Failed to update details\',
}).open()
}
});
$(document).on(\'click\', \'#update_password\', async function () {
var view = app.views.current
// Get the values from the password input fields
const password = $(\'input[name="password"]\').val().trim();
const current_password = $(\'input[name="current_password"]\').val().trim();
const confirmPassword = $(\'input[name="confirm_password"]\').val().trim();
if (current_password === \'\') {
showToast(\'Please enter your current password\', \'Error\');
return
}
if (password.length < 8) {
showToast(\'Password must be at least 8 characters long.\')
return
}
// Check if password contains at least one lowercase letter
if (!/[a-z]/.test(password)) {
showToast(\'Password must contain at least one lowercase letter.\')
return
}
// Check if password contains at least one uppercase letter
if (!/[A-Z]/.test(password)) {
showToast(\'Password must contain at least one uppercase letter.\')
return
}
// Check if password contains at least one number
if (!/d/.test(password)) {
showToast(\'Password must contain at least one number.\')
return
}
if (confirmPassword === \'\') {
showToast(\'Please confirm your password\', \'Error\');
return;
}
if (password !== confirmPassword) {
showToast(\'Passwords do not match\', \'Error\');
return;
}
try {
app.preloader.show()
const response = await updatePassword(password, current_password)
app.preloader.hide()
if (response && response.success) {
showToast(\'Password updated successfully\')
view.router.navigate(\'/profile/\')
return;
}
throw new Error(response.message);
} catch (error) {
app.preloader.hide()
app.notification.create({
titleRightText: \'now\',
subtitle: \'Oops, something went wrong\',
text: error.message || \'Failed to update password\',
}).open()
}
})
// --------------- End Edit Profile Page ---------------
// --------------- Edit Username Page ---------------
$(document).on(\'page:beforein\', \'.page[data-name="profile-edit-username"]\', async function (e) {
var view = app.views.current
const user = await getSessionUser()
if (!user) {
view.router.navigate(\'/login\')
return
}
// Example of how to fill in the form fields with the provided data
$(\'.profile-edit-view input[name="username"]\').val(user.username || \'\')
if (user.can_update_username) {
$(\'#username-editable\').remove()
} else {
document.querySelector(\'#username-editable\').innerText = `You can change your username in ${user.next_update_username} days`
}
})
$(document).on(\'click\', \'#save-username\', async function () {
var view = app.views.current
const user = await getSessionUser()
if (!user.can_update_username) {
return
}
const username = $(\'.profile-edit-view input[name="username"]\').val()
if (username === \'\') {
showToast(\'Please enter a username\', \'Error\')
return
}
// username can only have letters, numbers, and underscores
var usernamePattern = /^[a-zA-Z0-9_]+$/
if (!usernamePattern.test(username)) {
showToast(\'Username can only contain letters, numbers, and underscores\')
return
}
// username must be at least 3 characters long
if (username.length < 3) {
showToast(\'Username must be at least 3 characters long\')
return
}
if (username === user.username) {
return
}
try {
app.preloader.show()
const response = await updateUsername(username)
app.preloader.hide()
if (response && response.success) {
showToast(\'Username updated successfully\', \'Success\')
view.router.navigate(\'/profile/\')
store.dispatch(\'updateUserDetails\')
} else {
throw new Error(response.message)
}
} catch (error) {
app.preloader.hide()
app.notification.create({
titleRightText: \'now\',
subtitle: \'Oops, something went wrong\',
text: error.message || \'Failed to update username\',
}).open()
}
})
// --------------- End Edit Username Page ---------------
// --------------- Edit Profile images Page ---------------
$(document).on(\'page:init\', \'.page[data-name="profile-edit-images"]\', async function (e) {
var view = app.views.current
const user = await getSessionUser()
if (!user) {
view.router.navigate(\'/login\')
return
}
// If a cover photo exists, use it as the background image of the upload label
if (user.cover_image) {
$(\'input[name="cover_image"]\').closest(\'.custom-file-upload\').find(\'label\').css(\'background-image\', `url(\'${user.cover_image}\')`)
$(\'input[name="cover_image"]\').closest(\'.custom-file-upload\').find(\'label\').css(\'background-size\', \'cover\')
}
if (user.profile_image) {
$(\'input[name="profile_image"]\').closest(\'.custom-file-upload\').find(\'label\').css(\'background-image\', `url(\'${user.profile_image}\')`)
$(\'input[name="profile_image"]\').closest(\'.custom-file-upload\').find(\'label\').css(\'background-size\', \'contain\')
$(\'input[name="profile_image"]\').closest(\'.custom-file-upload\').find(\'label\').css(\'background-position\', \'center\')
$(\'input[name="profile_image"]\').closest(\'.custom-file-upload\').find(\'label\').css(\'background-repeat\', \'no-repeat\')
}
})
$(document).on(\'click\', \'#save-profile-images\', async function () {
var view = app.views.current
const cover_image = $(\'input[name="cover_image"]\').prop(\'files\')[0]
const profile_image = $(\'input[name="profile_image"]\').prop(\'files\')[0]
let coverBase64 = null
let profileBase64 = null
if (cover_image) {
// Wrap the FileReader in a Promise to wait for it to complete
coverBase64 = await new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(cover_image)
reader.onload = () => resolve(reader.result)
reader.onerror = () => reject(new Error(\'Failed to read image as base64\'))
})
}
if (profile_image) {
// Wrap the FileReader in a Promise to wait for it to complete
profileBase64 = await new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(profile_image)
reader.onload = () => resolve(reader.result)
reader.onerror = () => reject(new Error(\'Failed to read image as base64\'))
})
}
if (!coverBase64 && !profileBase64) {
return
}
try {
app.preloader.show()
let promises = []
if (profileBase64) {
promises.push(updateProfileImage(profileBase64))
}
if (coverBase64) {
promises.push(updateCoverImage(coverBase64))
}
const responses = await Promise.all(promises)
app.preloader.hide()
if (responses.every(response => response && response.success)) {
showToast(\'Images updated successfully\', \'Success\')
view.router.navigate(\'/profile/\')
store.dispatch(\'updateUserDetails\')
return
}
if (responses.some(response => response && !response.success)) {
throw new Error(\'Failed to update images\')
}
} catch (error) {
app.preloader.hide()
app.notification.create({
titleRightText: \'now\',
subtitle: \'Oops, something went wrong\',
text: error.message || \'Failed to update images\',
}).open()
}
})
$(document).on(\'change\', \'input[name="cover_image"]\', function (e) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = function (event) {
console.log($(\'.custom-file-upload.cover\'));
$(\'.custom-file-upload.cover\')
.find(\'label\')
.css(\'background-image\', `url(\'${event.target.result}\')`)
.css(\'background-size\', \'cover\');
};
if (file) {
reader.readAsDataURL(file);
}
});
$(document).on(\'change\', \'input[name="profile_image"]\', function (e) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = function (event) {
console.log($(\'.custom-file-upload.profile\'));
$(\'.custom-file-upload.profile\')
.find(\'label\')
.css(\'background-image\', `url(\'${event.target.result}\')`)
.css(\'background-size\', \'cover\');
};
if (file) {
reader.readAsDataURL(file);
}
});
// --------------- End Profile images Page ---------------
// --------------- Edit Socials Page ---------------
$(document).on(\'page:init\', \'.page[data-name="profile-edit-socials"]\', async function (e) {
var view = app.views.current
const user = await getSessionUser()
if (!user) {
view.router.navigate(\'/login\')
return
}
const externalLinks = user.profile_links || {};
app.popup.create({
el: \'.add-link-popup\',
swipeToClose: \'to-bottom\'
});
// Populate form fields
document.querySelector(\'input[name="social_instagram"]\').value = externalLinks.instagram || \'\';
document.querySelector(\'input[name="social_facebook"]\').value = externalLinks.facebook || \'\';
document.querySelector(\'input[name="social_tiktok"]\').value = externalLinks.tiktok || \'\';
document.querySelector(\'input[name="social_youtube"]\').value = externalLinks.youtube || \'\';
document.querySelector(\'input[name="social_mivia"]\').value = externalLinks.mivia || \'\';
document.querySelector(\'input[name="social_custodian"]\').value = externalLinks.custodian || \'\';
// .social-other-links ul
const externalLinksContainer = $(\'.social-other-links ul\')[0];
externalLinks.external_links?.forEach(linkObj => {
const listItem = document.createElement(\'li\');
listItem.innerHTML = `
<a class="item-link item-content" href="${linkObj.link.url}" data-link-id="${linkObj.id}">
<div class="item-inner">
<div class="item-title">
${linkObj.link.label}
</div>
<div class="item-after delete-external-link"><i class="icon f7-icons">xmark_circle</i></div>
</div>
</a>
`;
externalLinksContainer.appendChild(listItem);
});
})
// Add event listener for the Save button
$(document).on(\'click\', \'#add-link-btn\', async function () {
const linkTitle = $(\'input[name="custom_link_title"]\').val();
const linkUrl = $(\'input[name="custom_link_url"]\').val();
// Validate the inputs
if (linkTitle === \'\') {
console.log(\'Please enter a link title.\', $(\'input[name="custom_link_title"]\'));
showToast(\'Please enter a link title.\', \'Error\');
return;
}
if (linkUrl === \'\') {
showToast(\'Please enter a link URL.\', \'Error\');
return;
}
// Simple URL validation (basic check)
// const urlPattern = /^(https?://)?([da-z.-]+).([a-z.]{2,6})([/w .-]*)*/?$/;
// if (!urlPattern.test(linkUrl)) {
// showToast(\'Please enter a valid URL.\', \'Error\');
// return;
// }
const urlPattern = /^(https?://|www.)[da-z.-]+.[a-z]{2,6}/?$/;
if (!urlPattern.test(linkUrl)) {
showToast(\'Please enter a valid URL.\', \'Error\');
return;
}
// Mock API request (POST request)
const requestData = {
label: linkTitle,
url: linkUrl
};
app.popup.close()
app.preloader.show()
const response = await addUserProfileLinks({
type: \'external_links\',
link: requestData
})
if (response && response.success) {
showToast(\'Link added successfully\', \'Success\');
// Add the new link to the list
const listItem = document.createElement(\'li\');
listItem.innerHTML = `
<a class="item-link item-content" href="${linkUrl}" data-link-id="${response.id}">
<div class="item-inner">
<div class="item-title">
${linkTitle}
</div>
<div class="item-after"><i class="icon f7-icons delete-external-link">xmark_circle</i></div>
</div>
</a>
`;
const externalLinksContainer = $(\'.social-other-links ul\')[0];
externalLinksContainer.appendChild(listItem);
store.dispatch(\'updateUserDetails\')
}
app.preloader.hide()
});
// Save social links
$(document).on(\'click\', \'#save-profile-socials\', async function () {
var view = app.views.current
const user = await getSessionUser()
const instagram = $(\'input[name="social_instagram"]\').val();
const facebook = $(\'input[name="social_facebook"]\').val();
const tiktok = $(\'input[name="social_tiktok"]\').val();
const youtube = $(\'input[name="social_youtube"]\').val();
const mivia = $(\'input[name="social_mivia"]\').val();
const custodian = $(\'input[name="social_custodian"]\').val();
const links = {
instagram,
facebook,
tiktok,
youtube,
mivia,
custodian
};
// ig, tiktok, yt. mivia, custodian must be string, no special characters except for _ and - and . and
const usernamePattern = /^[a-zA-Z0-9._-]+$/;
if (instagram && !usernamePattern.test(instagram)) {
showToast(\'Please enter a valid Instagram username (letters, numbers, underscores, periods, hyphens only)\', \'Error\');
return;
}
if (tiktok && !usernamePattern.test(tiktok)) {
showToast(\'Please enter a valid TikTok username (letters, numbers, underscores, periods, hyphens only)\', \'Error\');
return;
}
if (youtube && !usernamePattern.test(youtube)) {
showToast(\'Please enter a valid YouTube username (letters, numbers, underscores, periods, hyphens only)\', \'Error\');
return;
}
if (mivia && !usernamePattern.test(mivia)) {
showToast(\'Please enter a valid Mivia username (letters, numbers, underscores, periods, hyphens only)\', \'Error\');
return;
}
if (custodian && !usernamePattern.test(custodian)) {
showToast(\'Please enter a valid Custodian username (letters, numbers, underscores, periods, hyphens only)\', \'Error\');
return;
}
// facebook must be a valid facebook url
const urlPattern = /^(https?://|www.)[da-z.-]+.[a-z]{2,6}/?$/;
if (facebook && !usernamePattern.test(facebook)) {
showToast(\'Please enter a valid Facebook username (letters, numbers, underscores, periods, hyphens only)\', \'Error\');
return;
}
// check if the request data is the same as userdata
let dirtied = false;
for (const key in links) {
if (links[key] !== user.profile_links[key]) {
dirtied = true
break;
}
}
if (!dirtied) {
return
}
app.preloader.show()
const response = await updateSocialLinks(links);
app.preloader.hide()
if (response && response.success) {
showToast(\'Social links updated successfully\', \'Success\');
view.router.navigate(\'/profile/\')
store.dispatch(\'updateUserDetails\')
} else {
showToast(\'Failed to update social links\', \'Error\');
}
})
// Delete link
$(document).on(\'click\', \'.delete-external-link\', async function (e) {
const linkId = e.target.closest(\'.item-link\').dataset.linkId;
// confirm dialog
app.dialog.confirm(\'Are you sure you want to delete this link?\', \'Delete Link\', async function () {
app.preloader.show()
const response = await removeProfileLink(linkId);
app.preloader.hide()
if (response) {
showToast(\'Link deleted successfully\', \'Success\')
// remove the link from the list
e.target.closest(\'.item-link\').remove();
store.dispatch(\'updateUserDetails\')
} else {
showToast(\'Failed to delete link\', \'Error\')
}
})
})
// --------------- End Edit Socials Page ---------------
$(document).on(\'input\', \'#lowercaseInput\', function (event) {
this.value = this.value.toLowerCase();
});
// --------------- Delete Profile Page ---------------
// $(document).on(\'page:init\', \'.page[data-name="profile-edit-account-settings"]\', function (e) {
// });
$(document).on(\'click\', \'.account-delete\', function (e) {
app.dialog.confirm(\'Are you sure? It is not possible to restore accounts once deleted.\', \'Confirm\', function (name) {
app.dialog.passwordConfirm(\'Please enter your password.\', \'Delete Account\', async function (password) {
await handleDeleteAccount(password);
});
});
});
async function handleDeleteAccount(password) {
try {
app.preloader.show();
const response = await deleteUserAccount(password);
app.preloader.hide();
if (!response) {
app.dialog.alert(\'Failed to delete account\', \'Error\');
return;
}
if (response && response.success == false) {
app.dialog.alert(response.message, \'Error\');
return;
}
if (response && response.success) {
app.dialog.alert(\'Account deleted successfully\', \'Success\');
setTimeout(() => {
store.dispatch(\'logout\');
}, 1000);
}
} catch (error) {
app.preloader.hide();
app.dialog.alert(error.message || \'Failed to delete account\', \'Error\');
}
}
// Custom dialog to ask for password
app.dialog.passwordConfirm = function (text, title, callback) {
app.dialog.create({
title: title,
text: text,
content: \'<div class="dialog-input-field item-input"><div class="item-input-wrap"><input type="password" name="password" placeholder="Enter your password" class="dialog-input"></div></div>\',
buttons: [{
text: \'Cancel\',
onClick: function (dialog, e) {
dialog.close();
}
},
{
text: \'Delete\',
bold: true,
onClick: function (dialog, e) {
var password = dialog.$el.find(\'.dialog-input\').val(); // Get the password entered
if (!password) {
showToast(\'Please enter your password\', \'Error\');
return;
}
callback(password); // Pass the password to the callback
dialog.close();
}
}
]
}).open();
};