Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f3109a68f
|
||
|
|
9ae23ce25e
|
||
|
|
c41f38ce6b | ||
|
|
5771f1372f | ||
|
|
73d61d76de | ||
|
|
50e2d95fda |
No files matched your search
@@ -24,10 +24,9 @@ const createMiddleware = (users) => {
|
||||
res.redirect("/login");
|
||||
return res.status(status.Unauthorized);
|
||||
}
|
||||
|
||||
|
||||
if (!req.session.user) {
|
||||
let user = await users.findOne({ _id: new ObjectId(req.session.userId) }).then((user) => user);
|
||||
|
||||
if (!user) {
|
||||
return req.session.destroy((err) => {
|
||||
if (err) {
|
||||
@@ -49,7 +48,7 @@ const createMiddleware = (users) => {
|
||||
console.error("Failed to save session: ", err);
|
||||
|
||||
return req.session.destroy((err) => {
|
||||
req.session.errMessage = "An error occured, please login again.";
|
||||
req.session.errMessage = "Failed to save session, please login again.";
|
||||
|
||||
if (err) {
|
||||
console.error("Failed to destroy session: ", err);
|
||||
|
||||
@@ -11,6 +11,7 @@ function lockAccount() {
|
||||
document.getElementById("password").disabled = true;
|
||||
document.getElementById("repassword").disabled = true;
|
||||
document.getElementById("save-account").classList.add("cursor-not-allowed");
|
||||
document.getElementById("save-account").classList.remove("cursor-pointer");
|
||||
|
||||
document.getElementById("edit-account").innerHTML = "Edit";
|
||||
document.getElementById("edit-account").onclick = unlockAccount;
|
||||
@@ -30,7 +31,12 @@ function lockPersonal() {
|
||||
document.getElementById("ms-married").disabled = true;
|
||||
document.getElementById("ms-divorced").disabled = true;
|
||||
document.getElementById("ms-widowed").disabled = true;
|
||||
document.getElementById("income").disabled = true;
|
||||
document.getElementById("expenses").disabled = true;
|
||||
document.getElementById("assets").disabled = true;
|
||||
document.getElementById("liabilities").disabled = true;
|
||||
document.getElementById("save-personal").classList.add("cursor-not-allowed");
|
||||
document.getElementById("save-personal").classList.remove("cursor-pointer");
|
||||
|
||||
document.getElementById("edit-personal").innerHTML = "Edit";
|
||||
document.getElementById("edit-personal").onclick = unlockPersonal;
|
||||
@@ -42,11 +48,12 @@ function lockPersonal() {
|
||||
*/
|
||||
function unlockAccount() {
|
||||
document.getElementById("save-account").disabled = false;
|
||||
// document.getElementById("email").disabled = false;
|
||||
document.getElementById("email").disabled = false;
|
||||
document.getElementById("name").disabled = false;
|
||||
document.getElementById("password").disabled = false;
|
||||
document.getElementById("repassword").disabled = false;
|
||||
document.getElementById("save-account").classList.remove("cursor-not-allowed");
|
||||
document.getElementById("save-account").classList.add("cursor-pointer");
|
||||
|
||||
document.getElementById("edit-account").innerHTML = "Cancel changes";
|
||||
document.getElementById("edit-account").onclick = lockAccount;
|
||||
@@ -64,7 +71,12 @@ function unlockPersonal() {
|
||||
document.getElementById("ms-married").disabled = false;
|
||||
document.getElementById("ms-divorced").disabled = false;
|
||||
document.getElementById("ms-widowed").disabled = false;
|
||||
document.getElementById("income").disabled = false;
|
||||
document.getElementById("expenses").disabled = false;
|
||||
document.getElementById("assets").disabled = false;
|
||||
document.getElementById("liabilities").disabled = false;
|
||||
document.getElementById("save-personal").classList.remove("cursor-not-allowed");
|
||||
document.getElementById("save-personal").classList.add("cursor-pointer");
|
||||
|
||||
document.getElementById("edit-personal").innerHTML = "Cancel changes";
|
||||
document.getElementById("edit-personal").onclick = lockPersonal;
|
||||
@@ -72,4 +84,4 @@ function unlockPersonal() {
|
||||
|
||||
// On page load, ensure forms are locked and reset
|
||||
lockAccount();
|
||||
// lockPersonal();
|
||||
lockPersonal();
|
||||
+130
-28
@@ -101,18 +101,17 @@ module.exports = (middleware, users, plans, assets) => {
|
||||
try {
|
||||
const userPlansFromDB = await plans.find({ userId: new ObjectId(req.session.userId) }).toArray();
|
||||
|
||||
// Use a for...of loop for proper async/await behavior in series for updates
|
||||
for (const plan of userPlansFromDB) {
|
||||
const percentage = await calculatePlanProgress(plan, assets, req.session.userId);
|
||||
await updatePlanProgressInDB(plan._id, percentage, plans); // Pass the 'plans' collection
|
||||
const percentage = await calculatePlanProgress(plan, assets, req.session.user._id);
|
||||
await updatePlanProgressInDB(plan._id, percentage, plans);
|
||||
}
|
||||
|
||||
// Re-fetch plans to get updated progress for rendering
|
||||
const updatedUserPlans = await plans.find({ userId: new ObjectId(req.session.userId) }).toArray();
|
||||
const updatedUserPlans = await plans.find({ userId: new ObjectId(req.session.user._id) }).toArray();
|
||||
|
||||
|
||||
res.render('plans', {
|
||||
user: req.session.user,
|
||||
plans: updatedUserPlans, // Send the most up-to-date plans
|
||||
plans: updatedUserPlans,
|
||||
geoData: req.session.geoData
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -141,16 +140,9 @@ module.exports = (middleware, users, plans, assets) => {
|
||||
return res.status(status.NotFound).redirect('/plans');
|
||||
}
|
||||
|
||||
// The plan.progress should be up-to-date from the database as it was updated in the /plans route
|
||||
// or when assets/plans are modified. If an immediate recalculation for this specific view is absolutely needed,
|
||||
// (e.g., if assets were modified without an immediate plan progress update elsewhere),
|
||||
// you could do it here:
|
||||
// const currentProgress = await calculatePlanProgress(plan, assets, req.session.user._id);
|
||||
// plan.progress = currentProgress; // This would only update the 'plan' object for this render, not in DB
|
||||
|
||||
res.render('planDetail', {
|
||||
user: req.session.user,
|
||||
plan: plan, // This plan object will have the progress from the database
|
||||
plan: plan,
|
||||
geoData: req.session.geoData,
|
||||
assets: userAssets,
|
||||
suggestions: await suggestions.generateSuggestions(),
|
||||
@@ -217,9 +209,10 @@ module.exports = (middleware, users, plans, assets) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/pun', async (req, res) => {
|
||||
const pun = await suggestions.generatePun();
|
||||
return res.status(status.Ok).json({ pun });
|
||||
router.post('/fact', async (req, res) => {
|
||||
const factInput = req.body.fact;
|
||||
const fact = await suggestions.generateFact(factInput);
|
||||
return res.status(status.Ok).json({ fact });
|
||||
});
|
||||
|
||||
router.get('/more', (req, res) => {
|
||||
@@ -271,10 +264,12 @@ module.exports = (middleware, users, plans, assets) => {
|
||||
const validationOptions = { convert: true, abortEarly: false };
|
||||
const { error, value } = questionnaireSchema.validate(req.body, validationOptions);
|
||||
|
||||
let referrer = req.get('Referrer') || "/home";
|
||||
if (error) {
|
||||
console.error("Questionnaire validation error:", error.details);
|
||||
req.session.errMessage = "Invalid input: " + error.details.map(d => d.message.replace(/"/g, '')).join(', ');
|
||||
res.status(status.BadRequest).redirect("/questionnaire");
|
||||
let redirect = referrer.includes("?profile") ? "/questionnaire?profile" : "/questionnaire";
|
||||
res.status(status.BadRequest).redirect(redirect);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -303,20 +298,34 @@ module.exports = (middleware, users, plans, assets) => {
|
||||
console.log(`User questionnaire data unchanged (already up-to-date): ${req.session.userId}`);
|
||||
}
|
||||
|
||||
req.session.user.financialData = true;
|
||||
req.session.errMessage = "";
|
||||
|
||||
req.session.save(err => {
|
||||
req.session.user = null; // set user to null so middleware updates user
|
||||
req.session.save((err) => {
|
||||
if (err) {
|
||||
res.status(status.InternalServerError).redirect("/plans");
|
||||
console.error("Failed to save session: ", err);
|
||||
|
||||
return req.session.destroy((err) => {
|
||||
req.session.errMessage = "Failed to save session, please login again.";
|
||||
|
||||
if (err) {
|
||||
console.error("Failed to destroy session: ", err);
|
||||
}
|
||||
|
||||
res.status(status.InternalServerError);
|
||||
return res.redirect("/login");
|
||||
});
|
||||
}
|
||||
res.status(status.Ok).redirect("/plans");
|
||||
|
||||
let redirect = referrer.includes("?profile") ? "/profile" :
|
||||
referrer != "/home" ? "/plans" : referrer;
|
||||
return res.status(status.Ok).redirect(redirect);
|
||||
});
|
||||
|
||||
}).catch(err => {
|
||||
console.error("Error updating questionnaire in database:", err);
|
||||
req.session.errMessage = "An error occurred while saving your information. Please try again.";
|
||||
res.status(status.InternalServerError).redirect("/questionnaire");
|
||||
let redirect = referrer.includes("?profile") ? "/questionnaire?profile" : "/questionnaire";
|
||||
res.status(status.InternalServerError).redirect(redirect);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -337,6 +346,7 @@ module.exports = (middleware, users, plans, assets) => {
|
||||
}
|
||||
|
||||
let update = {
|
||||
email: req.body.email,
|
||||
name: req.body.name,
|
||||
};
|
||||
|
||||
@@ -364,7 +374,25 @@ module.exports = (middleware, users, plans, assets) => {
|
||||
}
|
||||
|
||||
req.session.errMessage = "";
|
||||
return res.status(status.Ok).redirect("/profile");
|
||||
req.session.user = null; // set user to null so middleware updates user
|
||||
req.session.save((err) => {
|
||||
if (err) {
|
||||
console.error("Failed to save session: ", err);
|
||||
|
||||
return req.session.destroy((err) => {
|
||||
req.session.errMessage = "Failed to save session, please login again.";
|
||||
|
||||
if (err) {
|
||||
console.error("Failed to destroy session: ", err);
|
||||
}
|
||||
|
||||
res.status(status.InternalServerError);
|
||||
return res.redirect("/login");
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(status.Ok).redirect("/profile");
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error("Error updating account in database:", err);
|
||||
req.session.errMessage = "An error occurred while saving your information. Please try again.";
|
||||
@@ -372,7 +400,81 @@ module.exports = (middleware, users, plans, assets) => {
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/createAsset", async (req, res) => {
|
||||
router.post("/updatePersonal", (req, res) => {
|
||||
const questionnaireSchema = joi.object({
|
||||
dob: joi.date().required(),
|
||||
education: joi.string().valid('primary', 'secondary', 'tertiary', 'postgraduate').required(),
|
||||
maritalStatus: joi.string().valid('single', 'married', 'divorced', 'widowed').required(),
|
||||
income: joi.number().min(0).required(),
|
||||
expenses: joi.number().min(0).required(),
|
||||
assets: joi.number().min(0).required(),
|
||||
liabilities: joi.number().min(0).required(),
|
||||
});
|
||||
|
||||
const validationOptions = { convert: true, abortEarly: false };
|
||||
const { error, value } = questionnaireSchema.validate(req.body, validationOptions);
|
||||
|
||||
if (error) {
|
||||
console.error("Personal info validation error:", error.details);
|
||||
req.session.errMessage = "Invalid input: " + error.details.map(d => d.message.replace(/"/g, '')).join(', ');
|
||||
res.status(status.BadRequest).redirect("/profile");
|
||||
return;
|
||||
}
|
||||
|
||||
users.updateOne(
|
||||
{ _id: new ObjectId(req.session.userId) },
|
||||
{
|
||||
$set: {
|
||||
financialData: true,
|
||||
dob: value.dob,
|
||||
education: value.education,
|
||||
maritalStatus: value.maritalStatus,
|
||||
income: value.income,
|
||||
expenses: value.expenses,
|
||||
assets: value.assets,
|
||||
liabilities: value.liabilities,
|
||||
}
|
||||
}
|
||||
).then((result) => {
|
||||
if (result.matchedCount === 0) {
|
||||
console.log(`User not found during personal info update: ${req.session.userId}`);
|
||||
req.session.errMessage = "User session invalid. Please log in again.";
|
||||
res.status(status.NotFound).redirect("/login");
|
||||
return;
|
||||
}
|
||||
if (result.modifiedCount === 0 && result.matchedCount === 1) {
|
||||
console.log(`User personal info unchanged (already up-to-date): ${req.session.userId}`);
|
||||
}
|
||||
|
||||
req.session.errMessage = "";
|
||||
req.session.user = null; // set user to null so middleware updates user
|
||||
req.session.save((err) => {
|
||||
if (err) {
|
||||
console.error("Failed to save session: ", err);
|
||||
|
||||
return req.session.destroy((err) => {
|
||||
req.session.errMessage = "Failed to save session, please login again.";
|
||||
|
||||
if (err) {
|
||||
console.error("Failed to destroy session: ", err);
|
||||
}
|
||||
|
||||
res.status(status.InternalServerError);
|
||||
return res.redirect("/login");
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(status.Ok).redirect("/profile");
|
||||
});
|
||||
|
||||
}).catch(err => {
|
||||
console.error("Error updating personal info in database:", err);
|
||||
req.session.errMessage = "An error occurred while saving your information. Please try again.";
|
||||
res.status(status.InternalServerError).redirect("/profile");
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/createAsset", (req, res) => {
|
||||
// Create asset, each asset has different data structure based on type
|
||||
const type = req.body.type;
|
||||
const assetSchema = getAssetSchema(type);
|
||||
@@ -387,7 +489,7 @@ module.exports = (middleware, users, plans, assets) => {
|
||||
|
||||
if (valid.err) {
|
||||
req.session.errMessage = "Invalid input",
|
||||
res.status(status.BadRequest);
|
||||
res.status(status.BadRequest);
|
||||
return res.redirect("/assets");
|
||||
}
|
||||
|
||||
@@ -418,7 +520,7 @@ module.exports = (middleware, users, plans, assets) => {
|
||||
return res.status(status.Ok).redirect("/assets");
|
||||
});
|
||||
|
||||
router.post("/updateAsset", async (req, res) => {
|
||||
router.post("/updateAsset", (req, res) => {
|
||||
const type = req.body.type;
|
||||
const assetSchema = getAssetSchema(type);
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ const { GoogleGenAI } = require("@google/genai");
|
||||
|
||||
const ai = new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY });
|
||||
|
||||
async function generatePun() {
|
||||
async function generateFact(factInput) {
|
||||
const response = await ai.models.generateContent({
|
||||
model: "gemini-2.0-flash",
|
||||
contents: "Return a funny pun about investments, answer the pun only, no additional text.",
|
||||
contents: `Generate a concise investment fact about "${factInput}". If "${factInput}" is not directly investment-related, provide a general, useful investment fact instead. Deliver only the fact itself, with no extra text or explanation.`,
|
||||
});
|
||||
return response.text;
|
||||
}
|
||||
@@ -19,6 +19,6 @@ async function generateSuggestions() {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generatePun,
|
||||
generateFact,
|
||||
generateSuggestions
|
||||
};
|
||||
@@ -1,7 +1,14 @@
|
||||
<div data-dial-init class="fixed end-6 bottom-20 group">
|
||||
<button type="button" id="punButton" class="flex items-center justify-center text-white bg-blue-700 rounded-full w-14 h-14 hover:bg-blue-800 dark:bg-blue-600 dark:hover:bg-blue-700 focus:ring-4 focus:ring-blue-300 focus:outline-none dark:focus:ring-blue-800">
|
||||
<div class="fixed end-6 bottom-20 group">
|
||||
<div id="factMenu" class="absolute right-0 bottom-full mb-2 hidden">
|
||||
<div id="factContainer" class="bg-white p-4 rounded-lg shadow-md dark:bg-gray-700 w-64">
|
||||
<p class="mb-2 text-sm text-gray-700 dark:text-gray-300">Insert the kind of short fact you would like to know more about:</p>
|
||||
<input type="text" id="factInput" placeholder="Enter your topic here" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-600 dark:border-gray-500 dark:text-white dark:placeholder-gray-400">
|
||||
<button type="button" id="factSubmitButton" class="mt-3 w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-700">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="factButton" class="flex items-center justify-center text-white bg-blue-700 rounded-full w-14 h-14 hover:bg-blue-800 dark:bg-blue-600 dark:hover:bg-blue-700 focus:ring-4 focus:ring-blue-300 focus:outline-none dark:focus:ring-blue-800">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg>
|
||||
<span class="sr-only">Get a Pun</span>
|
||||
<span class="sr-only">Get a Fact</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -13,21 +20,35 @@
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script>
|
||||
const punButton = document.getElementById("punButton");
|
||||
punButton.addEventListener("click", () => {
|
||||
fetch("/pun")
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
Swal.fire('Here is a pun!', data.pun, 'success');
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error fetching pun:", error);
|
||||
Swal.fire('Error fetching pun', 'Please try again later', 'error');
|
||||
});
|
||||
const factButton = document.getElementById("factButton");
|
||||
const factMenu = document.getElementById("factMenu");
|
||||
const factInput = document.getElementById("factInput");
|
||||
const factSubmitButton = document.getElementById("factSubmitButton");
|
||||
|
||||
factButton.addEventListener("click", () => {
|
||||
factMenu.classList.toggle("hidden");
|
||||
});
|
||||
factSubmitButton.addEventListener("click", () => {
|
||||
fetch("/fact", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
fact: factInput.value,
|
||||
}),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
Swal.fire('Here is a fact!', data.fact, 'success');
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error fetching fact:", error);
|
||||
Swal.fire('Error fetching fact', 'Please try again later', 'error');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
+90
-49
@@ -73,6 +73,96 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Questionnare details -->
|
||||
<div class="mb-10 max-w-md mx-auto bg-white p-8 rounded-lg shadow-md">
|
||||
<div class="flex flex-row justify-between">
|
||||
<h3 class="pt-2 pr-2 pb-2">Personal information</h3>
|
||||
<% if (user.financialData) { %>
|
||||
<button id="edit-personal" onclick="unlockPersonal()" class="py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Edit</button>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<% if (user.financialData) { %>
|
||||
<form action="/updatePersonal" method="post" class="space-y-4" id="personal-form">
|
||||
<div>
|
||||
<label for="dob" class="block text-sm font-medium text-gray-700">Date of Birth</label>
|
||||
<input
|
||||
disabled
|
||||
id="dob"
|
||||
type="date"
|
||||
name="dob"
|
||||
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none"
|
||||
<% let year = typeof(user.dob) == "object" ? user.dob.getFullYear() : user.dob.split('-')[0]; %>
|
||||
<% let month = typeof(user.dob) == "object" ? user.dob.getMonth() : user.dob.split('-')[1] - 1; %>
|
||||
<% let day = typeof(user.dob) == "object" ? user.dob.getDate() + 1 : user.dob.split('-')[2].split('T')[0];%>
|
||||
<% let d = new Date(parseInt(year), parseInt(month), parseInt(day)); %>
|
||||
value="<%= d.getFullYear() + "-" + ("0"+(d.getMonth()+1)).slice(-2) + "-" + ("0" + d.getDate()).slice(-2); %>"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<label for="education" class="block text-sm font-medium text-gray-700">Education</label>
|
||||
<select disabled id="education" name="education" id="education" class="mt-1 block w-full px-3 py-2 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
<option <%= user.education == "primary" ? 'selected' : '' %> value="primary">Primary (Elementary)</option>
|
||||
<option <%= user.education == "secondary" ? 'selected' : '' %> value="secondary">Secondary (High School)</option>
|
||||
<option <%= user.education == "tertiary" ? 'selected' : '' %> value="tertiary">Tertiary (College/University)</option>
|
||||
<option <%= user.education == "postgraduate" ? 'selected' : '' %> value="postgraduate">Postgraduate (Master's/PhD)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Marital Status</label>
|
||||
<div class="mt-1 space-x-4">
|
||||
<label class="inline-flex items-center">
|
||||
<input disabled <%= user.maritalStatus == "single" ? 'checked' : '' %> id="ms-single" type="radio" name="maritalStatus" value="single" class="form-radio h-4 w-4 text-indigo-600 border-gray-300 focus:ring-indigo-500 disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
<span class="ml-2 text-sm text-gray-700">Single</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center">
|
||||
<input disabled <%= user.maritalStatus == "married" ? 'checked' : '' %> id="ms-married" type="radio" name="maritalStatus" value="married" class="form-radio h-4 w-4 text-indigo-600 border-gray-300 focus:ring-indigo-500 disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
<span class="ml-2 text-sm text-gray-700">Married</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center">
|
||||
<input disabled <%= user.maritalStatus == "divorced" ? 'checked' : '' %> id="ms-divorced" type="radio" name="maritalStatus" value="divorced" class="form-radio h-4 w-4 text-indigo-600 border-gray-300 focus:ring-indigo-500 disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
<span class="ml-2 text-sm text-gray-700">Divorced</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center">
|
||||
<input disabled <%= user.maritalStatus == "widowed" ? 'checked' : '' %> id="ms-widowed" type="radio" name="maritalStatus" value="widowed" class="form-radio h-4 w-4 text-indigo-600 border-gray-300 focus:ring-indigo-500 disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
<span class="ml-2 text-sm text-gray-700">Widowed</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="income" class="block text-sm font-medium text-gray-700">Annual Gross Income</label>
|
||||
<input disabled value="<%= user.income %>" id="income" type="number" name="income" min="0" placeholder="e.g., 50000" class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="expenses" class="block text-sm font-medium text-gray-700">Monthly Expenses</label>
|
||||
<input disabled value="<%= user.expenses %>" id="expenses" type="number" name="expenses" min="0" placeholder="e.g., 2000" class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="assets" class="block text-sm font-medium text-gray-700">Net Worth</label>
|
||||
<input disabled value="<%= user.assets %>" id="assets" type="number" name="assets" min="0" placeholder="Estimated Net Worth" class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="liabilities" class="block text-sm font-medium text-gray-700">Liabilities</label>
|
||||
<input disabled value="<%= user.liabilities %>" id="liabilities" type="number" name="liabilities" min="0" placeholder="Estimated Liabilities" class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button id="save-personal" disabled type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 cursor-not-allowed">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
<% } else { %>
|
||||
<div>
|
||||
<a href="/questionnaire?profile" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 cursor-pointer">Answer Questionnare</a>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Delete account -->
|
||||
<div class="flex flex-row justify-center mx-auto p8">
|
||||
<button
|
||||
type="submit"
|
||||
@@ -83,55 +173,6 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div class="mb-10 max-w-md mx-auto bg-white p-8 rounded-lg shadow-md">
|
||||
<div class="flex flex-row justify-between">
|
||||
<h3 class="pt-2 pr-2 pb-2">Personal information</h3>
|
||||
<button onclick="unlockPersonal()" class="py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Edit</button>
|
||||
</div>
|
||||
<form action="/updatePersonal" method="post" class="space-y-4" id="personal-form">
|
||||
<div>
|
||||
<label for="dob" class="block text-sm font-medium text-gray-700">Date of Birth</label>
|
||||
<input id="dob" disabled type="date" name="dob" class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
</div>
|
||||
<div>
|
||||
<label for="education" class="block text-sm font-medium text-gray-700">Education</label>
|
||||
<select disabled name="education" id="education" class="mt-1 block w-full px-3 py-2 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
<option value="primary">Primary (Elementary)</option>
|
||||
<option value="secondary">Secondary (High School)</option>
|
||||
<option value="tertiary">Tertiary (College/University)</option>
|
||||
<option value="postgraduate">Postgraduate (Master's/PhD)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Marital Status</label>
|
||||
<div class="mt-1 space-x-4">
|
||||
<label class="inline-flex items-center">
|
||||
<input disabled id="ms-single" type="radio" name="maritalStatus" value="single" class="form-radio h-4 w-4 text-indigo-600 border-gray-300 focus:ring-indigo-500 disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
<span class="ml-2 text-sm text-gray-700">Single</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center">
|
||||
<input disabled id="ms-married" type="radio" name="maritalStatus" value="married" class="form-radio h-4 w-4 text-indigo-600 border-gray-300 focus:ring-indigo-500 disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
<span class="ml-2 text-sm text-gray-700">Married</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center">
|
||||
<input disabled id="ms-divorced" type="radio" name="maritalStatus" value="divorced" class="form-radio h-4 w-4 text-indigo-600 border-gray-300 focus:ring-indigo-500 disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
<span class="ml-2 text-sm text-gray-700">Divorced</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center">
|
||||
<input disabled id="ms-widowed" type="radio" name="maritalStatus" value="widowed" class="form-radio h-4 w-4 text-indigo-600 border-gray-300 focus:ring-indigo-500 disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500 disabled:shadow-none">
|
||||
<span class="ml-2 text-sm text-gray-700">Widowed</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button id="save-personal" disabled type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 cursor-not-allowed">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div> -->
|
||||
|
||||
<div class="mt-24"></div>
|
||||
</main>
|
||||
|
||||
|
||||
Reference in new issue
Block a user