Add authentication #17
2 changed files with 174 additions and 101 deletions
|
@ -33,12 +33,14 @@ interface AuthElements {
|
||||||
editorResume: HTMLInputElement;
|
editorResume: HTMLInputElement;
|
||||||
editorCurrentResume: HTMLParagraphElement;
|
editorCurrentResume: HTMLParagraphElement;
|
||||||
saveProfileButton: HTMLButtonElement;
|
saveProfileButton: HTMLButtonElement;
|
||||||
|
sponsorViewToggle: HTMLDivElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StoreAuth {
|
export class StoreAuth {
|
||||||
private pb: PocketBase;
|
private pb: PocketBase;
|
||||||
private elements: AuthElements & { loadingSkeleton: HTMLDivElement };
|
private elements: AuthElements & { loadingSkeleton: HTMLDivElement };
|
||||||
private isEditingMemberId: boolean = false;
|
private isEditingMemberId: boolean = false;
|
||||||
|
private cachedUsers: any[] = []; // Store users data
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.pb = new PocketBase("https://pocketbase.ieeeucsd.org");
|
this.pb = new PocketBase("https://pocketbase.ieeeucsd.org");
|
||||||
|
@ -161,6 +163,10 @@ export class StoreAuth {
|
||||||
"saveProfileButton",
|
"saveProfileButton",
|
||||||
) as HTMLButtonElement;
|
) as HTMLButtonElement;
|
||||||
|
|
||||||
|
const sponsorViewToggle = document.getElementById(
|
||||||
|
"sponsorViewToggle",
|
||||||
|
) as HTMLDivElement;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!loginButton ||
|
!loginButton ||
|
||||||
!logoutButton ||
|
!logoutButton ||
|
||||||
|
@ -194,7 +200,8 @@ export class StoreAuth {
|
||||||
!editorPoints ||
|
!editorPoints ||
|
||||||
!editorResume ||
|
!editorResume ||
|
||||||
!editorCurrentResume ||
|
!editorCurrentResume ||
|
||||||
!saveProfileButton
|
!saveProfileButton ||
|
||||||
|
!sponsorViewToggle
|
||||||
) {
|
) {
|
||||||
throw new Error("Required DOM elements not found");
|
throw new Error("Required DOM elements not found");
|
||||||
}
|
}
|
||||||
|
@ -233,6 +240,7 @@ export class StoreAuth {
|
||||||
editorResume,
|
editorResume,
|
||||||
editorCurrentResume,
|
editorCurrentResume,
|
||||||
saveProfileButton,
|
saveProfileButton,
|
||||||
|
sponsorViewToggle,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,14 +253,14 @@ export class StoreAuth {
|
||||||
memberIdInput.disabled = true;
|
memberIdInput.disabled = true;
|
||||||
memberIdInput.value = user.member_id;
|
memberIdInput.value = user.member_id;
|
||||||
saveMemberId.textContent = "Update";
|
saveMemberId.textContent = "Update";
|
||||||
saveMemberId.classList.remove("btn-primary");
|
saveMemberId.classList.remove("enabled:btn-primary");
|
||||||
saveMemberId.classList.add("btn-ghost");
|
saveMemberId.classList.add("enabled:btn-ghost", "enabled:btn-outline");
|
||||||
} else {
|
} else {
|
||||||
// No member ID or editing - show save button and enable input
|
// No member ID or editing - show save button and enable input
|
||||||
memberIdInput.disabled = false;
|
memberIdInput.disabled = false;
|
||||||
saveMemberId.textContent = "Save";
|
saveMemberId.textContent = "Save";
|
||||||
saveMemberId.classList.remove("btn-ghost");
|
saveMemberId.classList.remove("enabled:btn-ghost", "enabled:btn-outline");
|
||||||
saveMemberId.classList.add("btn-primary");
|
saveMemberId.classList.add("enabled:btn-primary");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,6 +283,7 @@ export class StoreAuth {
|
||||||
loadingSkeleton,
|
loadingSkeleton,
|
||||||
officerViewToggle,
|
officerViewToggle,
|
||||||
officerContent,
|
officerContent,
|
||||||
|
sponsorViewToggle,
|
||||||
} = this.elements;
|
} = this.elements;
|
||||||
|
|
||||||
// Hide buttons initially
|
// Hide buttons initially
|
||||||
|
@ -284,16 +293,34 @@ export class StoreAuth {
|
||||||
if (this.pb.authStore.isValid && this.pb.authStore.model) {
|
if (this.pb.authStore.isValid && this.pb.authStore.model) {
|
||||||
// Update all the user information first
|
// Update all the user information first
|
||||||
const user = this.pb.authStore.model;
|
const user = this.pb.authStore.model;
|
||||||
|
const isSponsor = user.member_type === "IEEE Sponsor";
|
||||||
|
|
||||||
userName.textContent = user.name || "Name not provided";
|
userName.textContent = user.name || "Name not provided";
|
||||||
userEmail.textContent = user.email || "Email not available";
|
userEmail.textContent = user.email || "Email not available";
|
||||||
|
|
||||||
// Enable member ID input and save button
|
// Hide member ID and resume sections for sponsors
|
||||||
memberIdInput.disabled = false;
|
const memberIdSection = memberIdInput.closest('.space-y-1') as HTMLElement;
|
||||||
saveMemberId.disabled = false;
|
const resumeSection = resumeUpload.closest('.space-y-2')?.parentElement as HTMLElement;
|
||||||
|
const memberIdDivider = memberIdSection?.nextElementSibling as HTMLElement;
|
||||||
|
const resumeDivider = resumeSection?.nextElementSibling as HTMLElement;
|
||||||
|
|
||||||
// Enable resume upload
|
if (isSponsor) {
|
||||||
resumeUpload.disabled = false;
|
// Hide member ID and resume sections for sponsors
|
||||||
|
if (memberIdSection) memberIdSection.style.display = 'none';
|
||||||
|
if (memberIdDivider) memberIdDivider.style.display = 'none';
|
||||||
|
if (resumeSection) resumeSection.style.display = 'none';
|
||||||
|
if (resumeDivider) resumeDivider.style.display = 'none';
|
||||||
|
} else {
|
||||||
|
// Show and enable member ID input and save button for non-sponsors
|
||||||
|
if (memberIdSection) memberIdSection.style.display = '';
|
||||||
|
if (memberIdDivider) memberIdDivider.style.display = '';
|
||||||
|
if (resumeSection) resumeSection.style.display = '';
|
||||||
|
if (resumeDivider) resumeDivider.style.display = '';
|
||||||
|
|
||||||
|
memberIdInput.disabled = false;
|
||||||
|
saveMemberId.disabled = false;
|
||||||
|
resumeUpload.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Update member status
|
// Update member status
|
||||||
if (user.verified) {
|
if (user.verified) {
|
||||||
|
@ -330,8 +357,22 @@ export class StoreAuth {
|
||||||
memberStatus.classList.add("badge-warning"); // Red for administrators
|
memberStatus.classList.add("badge-warning"); // Red for administrators
|
||||||
} else if (user.member_type === "IEEE Officer") {
|
} else if (user.member_type === "IEEE Officer") {
|
||||||
memberStatus.classList.add("badge-info"); // Blue for officers
|
memberStatus.classList.add("badge-info"); // Blue for officers
|
||||||
|
} else if (user.member_type === "IEEE Sponsor") {
|
||||||
|
memberStatus.classList.add("badge-warning"); // Yellow for sponsors
|
||||||
} else {
|
} else {
|
||||||
memberStatus.classList.add("badge-neutral"); // Yellow for regular members
|
memberStatus.classList.add("badge-neutral"); // Neutral for regular members
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle view toggles visibility
|
||||||
|
const isOfficer = ["IEEE Officer", "IEEE Administrator"].includes(user.member_type || "");
|
||||||
|
const isSponsor = user.member_type === "IEEE Sponsor";
|
||||||
|
|
||||||
|
officerViewToggle.style.display = isOfficer ? "block" : "none";
|
||||||
|
sponsorViewToggle.style.display = isSponsor ? "block" : "none";
|
||||||
|
|
||||||
|
// If user is an officer or sponsor, preload the table data
|
||||||
|
if (isOfficer || isSponsor) {
|
||||||
|
await this.fetchUserResumes();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memberStatus.textContent = "Not Verified";
|
memberStatus.textContent = "Not Verified";
|
||||||
|
@ -369,20 +410,6 @@ export class StoreAuth {
|
||||||
resumeActions.style.display = "none";
|
resumeActions.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle officer view toggle visibility and data loading
|
|
||||||
const isOfficer = [
|
|
||||||
"IEEE Officer",
|
|
||||||
"IEEE Administrator",
|
|
||||||
"IEEE Events",
|
|
||||||
].includes(user.member_type || "");
|
|
||||||
|
|
||||||
officerViewToggle.style.display = isOfficer ? "block" : "none";
|
|
||||||
|
|
||||||
// If user is an officer, preload the table data
|
|
||||||
if (isOfficer) {
|
|
||||||
await this.fetchUserResumes();
|
|
||||||
}
|
|
||||||
|
|
||||||
// After everything is updated, show the content
|
// After everything is updated, show the content
|
||||||
loadingSkeleton.style.display = "none";
|
loadingSkeleton.style.display = "none";
|
||||||
userInfo.classList.remove("hidden");
|
userInfo.classList.remove("hidden");
|
||||||
|
@ -433,6 +460,7 @@ export class StoreAuth {
|
||||||
|
|
||||||
loginButton.style.display = "block";
|
loginButton.style.display = "block";
|
||||||
officerViewToggle.style.display = "none";
|
officerViewToggle.style.display = "none";
|
||||||
|
sponsorViewToggle.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,43 +614,63 @@ export class StoreAuth {
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleLogout() {
|
private handleLogout() {
|
||||||
|
// Clear auth store
|
||||||
this.pb.authStore.clear();
|
this.pb.authStore.clear();
|
||||||
|
|
||||||
|
// Clear cached users
|
||||||
|
this.cachedUsers = [];
|
||||||
|
|
||||||
|
// Reset member ID editing state
|
||||||
|
this.isEditingMemberId = false;
|
||||||
|
|
||||||
|
// Show all sections that might have been hidden
|
||||||
|
const memberIdSection = this.elements.memberIdInput.closest('.space-y-1') as HTMLElement;
|
||||||
|
const resumeSection = this.elements.resumeUpload.closest('.space-y-2')?.parentElement as HTMLElement;
|
||||||
|
const memberIdDivider = memberIdSection?.nextElementSibling as HTMLElement;
|
||||||
|
const resumeDivider = resumeSection?.nextElementSibling as HTMLElement;
|
||||||
|
|
||||||
|
// Show all sections
|
||||||
|
if (memberIdSection) memberIdSection.style.display = '';
|
||||||
|
if (memberIdDivider) memberIdDivider.style.display = '';
|
||||||
|
if (resumeSection) resumeSection.style.display = '';
|
||||||
|
if (resumeDivider) resumeDivider.style.display = '';
|
||||||
|
|
||||||
|
// Update UI
|
||||||
this.updateUI();
|
this.updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetchUserResumes(searchQuery: string = "") {
|
private async fetchUserResumes(searchQuery: string = "") {
|
||||||
try {
|
try {
|
||||||
let filter = ""; // Remove the resume filter to show all users
|
// Only fetch from API if we don't have cached data
|
||||||
|
if (this.cachedUsers.length === 0) {
|
||||||
|
const records = await this.pb.collection("users").getList(1, 50, {
|
||||||
|
sort: "-updated",
|
||||||
|
fields: "id,name,email,member_id,resume,points,collectionId,collectionName",
|
||||||
|
expand: "resume",
|
||||||
|
});
|
||||||
|
this.cachedUsers = records.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter cached data based on search query
|
||||||
|
let filteredUsers = this.cachedUsers;
|
||||||
if (searchQuery) {
|
if (searchQuery) {
|
||||||
const terms = searchQuery
|
const terms = searchQuery.toLowerCase().split(" ").filter(term => term.length > 0);
|
||||||
.toLowerCase()
|
|
||||||
.split(" ")
|
|
||||||
.filter((term) => term.length > 0);
|
|
||||||
if (terms.length > 0) {
|
if (terms.length > 0) {
|
||||||
const searchConditions = terms
|
filteredUsers = this.cachedUsers.filter(user => {
|
||||||
.map(
|
return terms.every(term =>
|
||||||
(term) =>
|
(user.name?.toLowerCase().includes(term) ||
|
||||||
`(name ?~ "${term}" || email ?~ "${term}" || member_id ?~ "${term}")`,
|
user.email?.toLowerCase().includes(term) ||
|
||||||
)
|
user.member_id?.toLowerCase().includes(term))
|
||||||
.join(" && ");
|
);
|
||||||
filter = searchConditions; // Only apply search conditions
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const records = await this.pb.collection("users").getList(1, 50, {
|
|
||||||
filter,
|
|
||||||
sort: "-updated",
|
|
||||||
fields:
|
|
||||||
"id,name,email,member_id,resume,points,collectionId,collectionName",
|
|
||||||
expand: "resume",
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Fetched records:", records.items); // Debug log
|
|
||||||
|
|
||||||
const { resumeList } = this.elements;
|
const { resumeList } = this.elements;
|
||||||
const fragment = document.createDocumentFragment();
|
const fragment = document.createDocumentFragment();
|
||||||
|
const isSponsor = this.pb.authStore.model?.member_type === "IEEE Sponsor";
|
||||||
|
|
||||||
if (records.items.length === 0) {
|
if (filteredUsers.length === 0) {
|
||||||
const row = document.createElement("tr");
|
const row = document.createElement("tr");
|
||||||
row.innerHTML = `
|
row.innerHTML = `
|
||||||
<td colspan="6" class="text-center py-4">
|
<td colspan="6" class="text-center py-4">
|
||||||
|
@ -631,14 +679,21 @@ export class StoreAuth {
|
||||||
`;
|
`;
|
||||||
fragment.appendChild(row);
|
fragment.appendChild(row);
|
||||||
} else {
|
} else {
|
||||||
records.items.forEach((user) => {
|
filteredUsers.forEach((user) => {
|
||||||
const row = document.createElement("tr");
|
const row = document.createElement("tr");
|
||||||
const resumeUrl =
|
const resumeUrl = user.resume && user.resume !== ""
|
||||||
user.resume && user.resume !== ""
|
? this.pb.files.getURL(user, user.resume.toString())
|
||||||
? this.pb.files.getURL(user, user.resume.toString())
|
: null;
|
||||||
: null;
|
|
||||||
|
|
||||||
console.log("User resume:", user.resume, "Resume URL:", resumeUrl); // Debug log
|
// Create edit button only if not a sponsor
|
||||||
|
const editButton = !isSponsor ? `
|
||||||
|
<button class="btn btn-ghost btn-xs edit-profile" data-user-id="${user.id}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
|
||||||
|
</svg>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
` : '';
|
||||||
|
|
||||||
row.innerHTML = `
|
row.innerHTML = `
|
||||||
<td class="block lg:table-cell">
|
<td class="block lg:table-cell">
|
||||||
|
@ -649,21 +704,11 @@ export class StoreAuth {
|
||||||
<div class="text-sm opacity-70">ID: ${user.member_id || "N/A"}</div>
|
<div class="text-sm opacity-70">ID: ${user.member_id || "N/A"}</div>
|
||||||
<div class="text-sm opacity-70">Points: ${user.points || 0}</div>
|
<div class="text-sm opacity-70">Points: ${user.points || 0}</div>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
${
|
${resumeUrl
|
||||||
resumeUrl
|
? `<a href="${resumeUrl}" target="_blank" class="btn btn-ghost btn-xs">View Resume</a>`
|
||||||
? `
|
: '<span class="text-sm opacity-50">No resume</span>'
|
||||||
<a href="${resumeUrl}" target="_blank" class="btn btn-ghost btn-xs">
|
|
||||||
View Resume
|
|
||||||
</a>
|
|
||||||
`
|
|
||||||
: '<span class="text-sm opacity-50">No resume</span>'
|
|
||||||
}
|
}
|
||||||
<button class="btn btn-ghost btn-xs edit-profile" data-user-id="${user.id}">
|
${editButton}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
|
||||||
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
|
|
||||||
</svg>
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -674,23 +719,13 @@ export class StoreAuth {
|
||||||
<td class="hidden lg:table-cell">${user.member_id || "N/A"}</td>
|
<td class="hidden lg:table-cell">${user.member_id || "N/A"}</td>
|
||||||
<td class="hidden lg:table-cell">${user.points || 0}</td>
|
<td class="hidden lg:table-cell">${user.points || 0}</td>
|
||||||
<td class="hidden lg:table-cell">
|
<td class="hidden lg:table-cell">
|
||||||
${
|
${resumeUrl
|
||||||
resumeUrl
|
? `<a href="${resumeUrl}" target="_blank" class="btn btn-ghost btn-xs">View Resume</a>`
|
||||||
? `
|
: '<span class="text-sm opacity-50">No resume</span>'
|
||||||
<a href="${resumeUrl}" target="_blank" class="btn btn-ghost btn-xs">
|
|
||||||
View Resume
|
|
||||||
</a>
|
|
||||||
`
|
|
||||||
: '<span class="text-sm opacity-50">No resume</span>'
|
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td class="hidden lg:table-cell">
|
<td class="hidden lg:table-cell">
|
||||||
<button class="btn btn-ghost btn-xs edit-profile" data-user-id="${user.id}">
|
${editButton}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
|
||||||
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
|
|
||||||
</svg>
|
|
||||||
Edit Profile
|
|
||||||
</button>
|
|
||||||
</td>
|
</td>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -701,16 +736,18 @@ export class StoreAuth {
|
||||||
resumeList.innerHTML = "";
|
resumeList.innerHTML = "";
|
||||||
resumeList.appendChild(fragment);
|
resumeList.appendChild(fragment);
|
||||||
|
|
||||||
// Setup edit profile event listeners
|
// Setup edit profile event listeners only if not a sponsor
|
||||||
const editButtons = resumeList.querySelectorAll(".edit-profile");
|
if (!isSponsor) {
|
||||||
editButtons.forEach((button) => {
|
const editButtons = resumeList.querySelectorAll(".edit-profile");
|
||||||
button.addEventListener("click", () => {
|
editButtons.forEach((button) => {
|
||||||
const userId = (button as HTMLButtonElement).dataset.userId;
|
button.addEventListener("click", () => {
|
||||||
if (userId) {
|
const userId = (button as HTMLButtonElement).dataset.userId;
|
||||||
this.handleProfileEdit(userId);
|
if (userId) {
|
||||||
}
|
this.handleProfileEdit(userId);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to fetch user resumes:", err);
|
console.error("Failed to fetch user resumes:", err);
|
||||||
const { resumeList } = this.elements;
|
const { resumeList } = this.elements;
|
||||||
|
@ -852,23 +889,19 @@ export class StoreAuth {
|
||||||
this.handleMemberIdButton(),
|
this.handleMemberIdButton(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Search functionality with minimal debounce
|
// Search functionality
|
||||||
let searchTimeout: NodeJS.Timeout;
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
const searchQuery = this.elements.resumeSearch.value.trim();
|
const searchQuery = this.elements.resumeSearch.value.trim();
|
||||||
this.fetchUserResumes(searchQuery);
|
this.fetchUserResumes(searchQuery);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Real-time search with minimal debounce
|
// Real-time search
|
||||||
this.elements.resumeSearch.addEventListener("input", () => {
|
this.elements.resumeSearch.addEventListener("input", handleSearch);
|
||||||
clearTimeout(searchTimeout);
|
|
||||||
searchTimeout = setTimeout(handleSearch, 150); // Reduced to 150ms for faster response
|
|
||||||
});
|
|
||||||
|
|
||||||
// Keep the click handler for the search button
|
// Search button click handler
|
||||||
this.elements.searchResumes.addEventListener("click", handleSearch);
|
this.elements.searchResumes.addEventListener("click", handleSearch);
|
||||||
|
|
||||||
// Officer view toggle event listener - now just toggles visibility
|
// Officer view toggle event listener
|
||||||
this.elements.officerViewCheckbox.addEventListener("change", (e) => {
|
this.elements.officerViewCheckbox.addEventListener("change", (e) => {
|
||||||
const isChecked = (e.target as HTMLInputElement).checked;
|
const isChecked = (e.target as HTMLInputElement).checked;
|
||||||
const storeItemsContainer = document.getElementById("storeItemsGrid");
|
const storeItemsContainer = document.getElementById("storeItemsGrid");
|
||||||
|
@ -878,11 +911,40 @@ export class StoreAuth {
|
||||||
storeItemsContainer.style.display = isChecked ? "none" : "grid";
|
storeItemsContainer.style.display = isChecked ? "none" : "grid";
|
||||||
}
|
}
|
||||||
officerContent.style.display = isChecked ? "block" : "none";
|
officerContent.style.display = isChecked ? "block" : "none";
|
||||||
|
|
||||||
|
// Uncheck sponsor view if officer view is checked
|
||||||
|
if (isChecked) {
|
||||||
|
const sponsorCheckbox = this.elements.sponsorViewToggle.querySelector('input[type="checkbox"]') as HTMLInputElement;
|
||||||
|
if (sponsorCheckbox) {
|
||||||
|
sponsorCheckbox.checked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sponsor view toggle event listener
|
||||||
|
const sponsorCheckbox = this.elements.sponsorViewToggle.querySelector('input[type="checkbox"]') as HTMLInputElement;
|
||||||
|
if (sponsorCheckbox) {
|
||||||
|
sponsorCheckbox.addEventListener("change", (e) => {
|
||||||
|
const isChecked = (e.target as HTMLInputElement).checked;
|
||||||
|
const storeItemsContainer = document.getElementById("storeItemsGrid");
|
||||||
|
const { officerContent } = this.elements;
|
||||||
|
|
||||||
|
if (storeItemsContainer) {
|
||||||
|
storeItemsContainer.style.display = isChecked ? "none" : "grid";
|
||||||
|
}
|
||||||
|
officerContent.style.display = isChecked ? "block" : "none";
|
||||||
|
|
||||||
|
// Uncheck officer view if sponsor view is checked
|
||||||
|
if (isChecked) {
|
||||||
|
this.elements.officerViewCheckbox.checked = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh resumes button event listener
|
// Refresh resumes button event listener
|
||||||
this.elements.refreshResumes.addEventListener("click", () => {
|
this.elements.refreshResumes.addEventListener("click", () => {
|
||||||
this.elements.resumeSearch.value = ""; // Clear search when refreshing
|
this.elements.resumeSearch.value = ""; // Clear search when refreshing
|
||||||
|
this.cachedUsers = []; // Clear the cache to force a new fetch
|
||||||
this.fetchUserResumes();
|
this.fetchUserResumes();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,17 @@
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="sponsorViewToggle" class="hidden">
|
||||||
|
<label
|
||||||
|
class="flex items-center justify-between w-full px-1 bg-base-200 rounded-lg"
|
||||||
|
>
|
||||||
|
<span class="text-sm">Sponsor View</span>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="toggle toggle-warning"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<div class="divider my-0.5"></div>
|
<div class="divider my-0.5"></div>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<label class="text-sm opacity-70">IEEE Member ID</label>
|
<label class="text-sm opacity-70">IEEE Member ID</label>
|
||||||
|
@ -123,7 +134,7 @@
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
id="saveMemberId"
|
id="saveMemberId"
|
||||||
class="btn h-8 min-h-[2rem] disabled:bg-base-300 disabled:border-2 disabled:border-opacity-50 disabled:cursor-not-allowed enabled:btn-primary"
|
class="btn h-8 min-h-[2rem] disabled:bg-base-300 disabled:border-2 disabled:border-opacity-50 disabled:cursor-not-allowed enabled:btn-primary hover:enabled:bg-primary-focus"
|
||||||
disabled>Save</button
|
disabled>Save</button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue