From 558a45862e95393c86c5d31fe20cb92ba04a29b5 Mon Sep 17 00:00:00 2001 From: Lakshay Manchanda Date: Mon, 23 Sep 2024 01:10:01 +0530 Subject: [PATCH 1/8] New UI for profile update requests page --- index.html | 4 +- profile-diff/assets/left-arrow.svg | 3 + profile-diff/constants.js | 22 ++ profile-diff/index.html | 29 +++ profile-diff/local-utils.js | 100 ++++++++ profile-diff/script.js | 320 +++++++++++++++++++++++++ profile-diff/style.css | 352 ++++++++++++++++++++++++++++ profile-diffs/assets/search.svg | 5 + profile-diffs/assets/sort-asc.svg | 4 + profile-diffs/assets/sort-desc.svg | 4 + profile-diffs/constants.js | 19 ++ profile-diffs/index.html | 60 +++++ profile-diffs/local-utils.js | 53 +++++ profile-diffs/script.js | 298 ++++++++++++++++++++++++ profile-diffs/style.css | 359 +++++++++++++++++++++++++++++ 15 files changed, 1631 insertions(+), 1 deletion(-) create mode 100644 profile-diff/assets/left-arrow.svg create mode 100644 profile-diff/constants.js create mode 100644 profile-diff/index.html create mode 100644 profile-diff/local-utils.js create mode 100644 profile-diff/script.js create mode 100644 profile-diff/style.css create mode 100644 profile-diffs/assets/search.svg create mode 100644 profile-diffs/assets/sort-asc.svg create mode 100644 profile-diffs/assets/sort-desc.svg create mode 100644 profile-diffs/constants.js create mode 100644 profile-diffs/index.html create mode 100644 profile-diffs/local-utils.js create mode 100644 profile-diffs/script.js create mode 100644 profile-diffs/style.css diff --git a/index.html b/index.html index aea4c8e4..5d38c77b 100644 --- a/index.html +++ b/index.html @@ -86,7 +86,9 @@ Create Goals Create Tasks - Profile + + Profile Update Requests + + + diff --git a/profile-diff/constants.js b/profile-diff/constants.js new file mode 100644 index 00000000..0342e1af --- /dev/null +++ b/profile-diff/constants.js @@ -0,0 +1,22 @@ +const YEARS_OF_EXPERIENCE = 'yoe'; + +const fieldDisplayName = { + first_name: 'First name', + last_name: 'Last name', + designation: 'Role', + company: 'Company', + yoe: 'Years of experience', + email: 'Email', + phone: 'Phone no.', + linkedin_id: 'Linkedin', + github_id: 'Github', + twitter_id: 'Twitter', + instagram_id: 'Instagram', + website: 'Website', +}; + +const Status = { + APPROVED: 'APPROVED', + PENDING: 'PENDING', + NOT_APPROVED: 'NOT APPROVED', +}; diff --git a/profile-diff/index.html b/profile-diff/index.html new file mode 100644 index 00000000..17487406 --- /dev/null +++ b/profile-diff/index.html @@ -0,0 +1,29 @@ + + + + + + + + Profile Diff + + + +
+ + Back + + Request Details +
+ +
+ + + + + + + diff --git a/profile-diff/local-utils.js b/profile-diff/local-utils.js new file mode 100644 index 00000000..64aaff40 --- /dev/null +++ b/profile-diff/local-utils.js @@ -0,0 +1,100 @@ +const getProfileDiff = async (id) => { + try { + const finalUrl = `${API_BASE_URL}/profileDiffs/${id}`; + const res = await fetch(finalUrl, { + credentials: 'include', + method: 'GET', + headers: { + 'Content-type': 'application/json', + }, + }); + if (res.status === 401) { + return { notAuthorized: true }; + } + if (res.status === 404) { + return { profileDiffExist: false }; + } + return { profileDiffExist: true, ...(await res.json()).profileDiff }; + } catch (err) { + throw err; + } +}; + +const fetchUser = async (userId) => { + try { + const userResponse = await fetch(`${API_BASE_URL}/users?id=${userId}`, { + method: 'GET', + credentials: 'include', + headers: { + 'Content-type': 'application/json', + }, + }); + if (userResponse.status === 404) { + return { userExist: false }; + } + const { user } = await userResponse.json(); + return { ...user, userExist: true }; + } catch (err) { + throw err; + } +}; + +function getDataItem(data, itemName) { + const item = data[itemName]; + + if (item) { + return item; + } else { + if (itemName === YEARS_OF_EXPERIENCE && item === 0) return item; + else return ''; + } +} + +function checkDifferentValues(primaryData, secondaryData) { + const diffValues = new Set(); + + for (const listItem in primaryData) { + const oldValue = getDataItem(primaryData, listItem); + const newValue = getDataItem(secondaryData, listItem); + const isValueEqual = String(oldValue).trim() === String(newValue).trim(); + + if (!isValueEqual) { + diffValues.add(listItem); + } + } + + return diffValues; +} + +function wantedData(data) { + const { + id, + first_name, + last_name, + email, + phone, + yoe, + company, + designation, + github_id, + linkedin_id, + twitter_id, + instagram_id, + website, + } = data; + return { + id, + first_name, + last_name, + email, + phone, + yoe, + company, + designation, + github_id, + linkedin_id, + twitter_id, + instagram_id, + website, + }; +} diff --git a/profile-diff/script.js b/profile-diff/script.js new file mode 100644 index 00000000..fb1443d9 --- /dev/null +++ b/profile-diff/script.js @@ -0,0 +1,320 @@ +const CONTAINER = document.querySelector('.container'); +let expanded = false; +let profileDetailsContainer; +let reasonHeading; + +const toast = document.getElementById('toast'); + +function showToast({ message, type }) { + toast.innerText = message; + + if (type === 'success') { + toast.classList.add('success'); + toast.classList.remove('failure'); + } else { + toast.classList.add('failure'); + toast.classList.remove('success'); + } + + toast.classList.remove('hidden'); + toast.classList.add('animated_toast'); + + setTimeout(() => { + toast.classList.add('hidden'); + toast.classList.remove('animated_toast'); + }, 3000); +} + +function renderProfileDetails(user, profileDiff) { + if (profileDetailsContainer) profileDetailsContainer.remove(); + profileDetailsContainer = createElement({ + type: 'div', + attributes: { class: 'profile-details-container' }, + }); + + CONTAINER.insertBefore(profileDetailsContainer, reasonHeading); + + const { id, ...oldData } = wantedData(user); + const { id: profileDiffId, ...newData } = wantedData(profileDiff); + + const difference = checkDifferentValues(oldData, newData); + + const fields = [ + 'first_name', + 'last_name', + 'designation', + 'company', + 'yoe', + 'email', + 'phone', + 'linkedin_id', + 'github_id', + 'twitter_id', + 'instagram_id', + 'website', + ]; + + let i = 0; + fields.forEach((field, index) => { + if (difference.has(field) || expanded) { + i++; + const profileDetailsListItem = createElement({ + type: 'div', + attributes: { + class: `profile-details-list-item ${ + expanded + ? fields.length - 1 === index + ? 'profile-details-border-none' + : '' + : i === difference.size + ? 'profile-details-border-none' + : '' + }`, + }, + }); + + const profileDetailsName = createElement({ + type: 'div', + attributes: { class: 'profile-details-name' }, + }); + + profileDetailsName.innerHTML = fieldDisplayName[field]; + profileDetailsListItem.appendChild(profileDetailsName); + if (difference.has(field)) { + const profileDetailsOldData = createElement({ + type: 'div', + attributes: { class: 'profile-details-old-data' }, + }); + profileDetailsOldData.innerHTML = oldData[field] || '—'; + + const profileDetailsNewData = createElement({ + type: 'div', + attributes: { class: 'profile-details-new-data' }, + }); + profileDetailsNewData.innerHTML = newData[field] || ''; + + profileDetailsListItem.appendChild(profileDetailsOldData); + profileDetailsListItem.appendChild(profileDetailsNewData); + } else { + const profileDetailsData = createElement({ + type: 'div', + attributes: { class: 'profile-details-data' }, + }); + profileDetailsData.innerHTML = oldData[field] || ''; + profileDetailsListItem.appendChild(profileDetailsData); + } + profileDetailsContainer.appendChild(profileDetailsListItem); + } + }); +} + +async function setUser(profileDiff) { + let user; + try { + user = await fetchUser(profileDiff.userId); + } catch (err) {} + if (!user.userExist) { + } + + CONTAINER.innerHTML = ''; + + const displayImage = createElement({ + type: 'img', + attributes: { + class: 'user_image', + src: user.picture.url, + height: '71px', + width: '71px', + }, + }); + CONTAINER.appendChild(displayImage); + + const username = createElement({ + type: 'div', + attributes: { + class: 'user_name', + }, + }); + username.innerHTML = `${user.first_name} ${user.last_name}`; + CONTAINER.appendChild(username); + + const expandControlContainer = createElement({ + type: 'div', + attributes: { class: 'expand-control-container' }, + }); + const expandTextDiv = createElement({ + type: 'div', + attributes: { class: 'expand-control-text' }, + }); + expandControlContainer.appendChild(expandTextDiv); + expandTextDiv.innerHTML = `See ${ + expanded ? 'Less' : 'All' + }`; + + expandTextDiv.addEventListener('click', () => { + expanded = !expanded; + expandTextDiv.innerHTML = `See ${ + expanded ? 'Less' : 'All' + }`; + renderProfileDetails(user, profileDiff); + }); + CONTAINER.appendChild(expandControlContainer); + renderProfileDetails(user, profileDiff); + reasonHeading = createElement({ + type: 'p', + attributes: { + class: 'reason_heading', + }, + }); + reasonHeading.innerHTML = 'Reason ( Optional )'; + CONTAINER.appendChild(reasonHeading); + + const reasonTextArea = createElement({ + type: 'textarea', + attributes: { + class: 'reason_textarea', + rows: 4, + }, + }); + CONTAINER.appendChild(reasonTextArea); + + const buttonsDiv = createElement({ + type: 'div', + attributes: { + class: 'button__container', + }, + }); + + const approvalButton = createElement({ + type: 'button', + attributes: { + class: 'button__approve', + }, + }); + approvalButton.innerHTML = 'Approve'; + buttonsDiv.appendChild(approvalButton); + + const rejectButton = createElement({ + type: 'button', + attributes: { + class: 'button__reject', + }, + }); + rejectButton.innerHTML = 'Reject'; + buttonsDiv.appendChild(rejectButton); + + approvalButton.onclick = async () => { + approvalButton.innerHTML = '
'; + approvalButton.disabled = true; + rejectButton.disabled = true; + try { + const response = await fetch(`${API_BASE_URL}/users/${user.id}`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify({ + id: profileDiff.id, + message: reasonTextArea.value, + }), + }); + + if (response.ok) { + showToast({ + type: 'success', + message: 'The Profile changes are Approved!', + }); + setTimeout(() => { + window.location.href = '/profile-diffs'; + }, 3000); + } else { + showToast({ type: 'error', message: 'Something went wrong!' }); + approvalButton.innerHTML = 'Approve'; + approvalButton.disabled = false; + rejectButton.disabled = false; + } + } catch (error) { + showToast({ type: 'error', message: 'Something went wrong!' }); + approvalButton.innerHTML = 'Approve'; + approvalButton.disabled = false; + rejectButton.disabled = false; + } + }; + + rejectButton.onclick = async () => { + rejectButton.innerHTML = '
'; + approvalButton.disabled = true; + rejectButton.disabled = true; + try { + const response = await fetch(`${API_BASE_URL}/users/rejectDiff`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify({ + profileDiffId: profileDiff.id, + message: reasonTextArea.value, + }), + }); + + if (response.ok) { + showToast({ + type: 'success', + message: 'The Profile changes are Rejected!', + }); + setTimeout(() => { + window.location.href = '/profile-diffs'; + }, 3000); + } else { + showToast({ type: 'error', message: 'Something went wrong!' }); + rejectButton.innerHTML = 'Reject'; + approvalButton.disabled = false; + rejectButton.disabled = false; + } + } catch (error) { + showToast({ type: 'error', message: 'Something went wrong!' }); + rejectButton.innerHTML = 'Reject'; + approvalButton.disabled = false; + rejectButton.disabled = false; + } + }; + + CONTAINER.appendChild(buttonsDiv); +} + +async function render() { + CONTAINER.innerHTML = '
'; + const id = new URLSearchParams(window.location.search).get('id'); + if (id) { + let profileDiff; + try { + profileDiff = await getProfileDiff(id); + } catch { + CONTAINER.innerHTML = 'Something went wrong fetching Profile Diff!'; + return; + } + if (profileDiff.notAuthorized) { + CONTAINER.innerHTML = 'You are not AUTHORIZED to view this page!'; + return; + } + if (!profileDiff.profileDiffExist) { + CONTAINER.innerHTML = 'Profile Diff not found!'; + return; + } + if (profileDiff.approval === Status.PENDING) { + await setUser(profileDiff); + } else { + CONTAINER.innerHTML = `The request status is ${profileDiff.approval}`; + } + } else { + CONTAINER.innerHTML = `No id found!`; + } +} + +render(); diff --git a/profile-diff/style.css b/profile-diff/style.css new file mode 100644 index 00000000..335f3261 --- /dev/null +++ b/profile-diff/style.css @@ -0,0 +1,352 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'); + +:root { + --blue-color: #1d1283; + --blue-hover-color: #11085c; + --dark-blue: #1b1378; + --light-aqua: #d4f9f2; + --scandal: #e5fcf5; + --green-transparent: rgba(0, 255, 0, 0.2); + --green-color: green; + --red-transparent: rgba(255, 0, 0, 0.145); + --white: #ffffff; + --black-transparent: #000000a8; + --black: #181717; + --light-gray: #d9d9d9; + --razzmatazz: #df0057; + --red-color: red; + --gray: #808080; + --button-proceed: #008000; + --modal-color: #00000048; + --black-color: black; + --light-gray-color: lightgray; + --green10: #e1f9f1; + --green500: #19805e; + --secondary10: #fff0f6; + --secondary600: #b6004e; + --medium-gray: #aeaeae; + --dark-gray: #737373; + --blue-color-heading: #041187; + --white-gray: #f2f2f3; + --color-red: #ae1820; + --color-green: rgba(0, 128, 0, 0.8); + --color-warn: rgba(199, 129, 18, 0.8); +} + +*, +::after, +::before { + box-sizing: border-box; +} + +body { + font-family: 'Roboto', sans-serif; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + min-height: 100vh; + user-select: none; + max-width: 100vw; + background-color: #f8fafd; +} + +.header { + height: 7.25em; + background-color: #233876; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + font-family: 'Inter', sans-serif; + font-optical-sizing: auto; + font-weight: 500; + font-style: normal; + font-size: 20px; + color: var(--white); + position: relative; +} + +.back { + background-color: transparent; + border: none; + padding: 10px; + text-decoration: none; + display: flex; + align-items: center; + position: absolute; + left: 10%; +} + +.back__icon { + height: 1.6rem; +} + +.container { + margin: 0 auto; + padding: 2em 0; + display: flex; + flex-direction: column; + align-items: center; + gap: 1em; + font-family: 'Inter', sans-serif; + font-weight: 700; + font-size: x-large; + text-align: center; + width: 95%; + max-width: 992px; +} + +.user_image { + border-radius: 37px; +} + +.user_name { + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 500; + font-size: 20px; + line-height: 150%; + color: #111928; + margin-top: -1em; + margin-bottom: 1em; +} + +.expand-control-container { + width: 100%; + display: flex; + justify-content: end; + align-items: center; + color: #233876; + font-family: 'Inter', sans-serif; + font-weight: 400; + font-size: 14px; +} + +.expand-control-text { + cursor: pointer; +} + +.expand-control-icon { + margin-left: 0.5em; + font-size: 10px !important; +} + +.reason_heading { + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 500; + font-size: 17px; + line-height: 150%; + color: #111928; + width: 100%; + text-align: left; + padding-left: 1.25em; + margin-block-end: 0; +} + +.reason_textarea { + font-family: 'Inter', sans-serif; + font-style: normal; + font-size: 16px; + background: #ffffff; + box-shadow: 0px 8px 3px rgba(0, 0, 0, 0.01), 0px 5px 3px rgba(0, 0, 0, 0.02), + 0px 2px 2px rgba(0, 0, 0, 0.04), 0px 1px 1px rgba(0, 0, 0, 0.04); + border-radius: 12px; + border: none; + padding: 1em; + width: 100%; + resize: none; +} + +.button__container { + width: 100%; + display: flex; + justify-content: space-between; + margin-top: 1em; +} + +.button__approve { + padding: 11px 32px; + background: #046c4e; + border-radius: 10px; + border: none; + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 500; + font-size: 18px; + line-height: 150%; + color: #ffffff; + cursor: pointer; +} + +.button__approve:disabled { + opacity: 0.2; +} + +.button__reject { + padding: 11px 32px; + background: #c81e1e; + border-radius: 10px; + border: none; + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 500; + font-size: 18px; + line-height: 150%; + color: #ffffff; + cursor: pointer; +} + +.button__reject:disabled { + opacity: 0.2; +} + +.loader { + width: 60px; + aspect-ratio: 2; + --_g: no-repeat radial-gradient(circle closest-side, #000 90%, #0000); + background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%; + background-size: calc(100% / 3) 50%; + animation: l3 1s infinite linear; +} + +.button__loader { + width: 60px; + aspect-ratio: 2; + --_g: no-repeat radial-gradient(circle closest-side, #fff 90%, #0000); + background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%; + background-size: calc(100% / 3) 50%; + animation: l3 1s infinite linear; +} + +@keyframes l3 { + 20% { + background-position: 0% 0%, 50% 50%, 100% 50%; + } + 40% { + background-position: 0% 100%, 50% 0%, 100% 50%; + } + 60% { + background-position: 0% 50%, 50% 100%, 100% 0%; + } + 80% { + background-position: 0% 50%, 50% 50%, 100% 100%; + } +} + +.profile-details-container { + background: #ffffff; + box-shadow: 0px 8px 3px rgba(0, 0, 0, 0.01), 0px 5px 3px rgba(0, 0, 0, 0.02), + 0px 2px 2px rgba(0, 0, 0, 0.04), 0px 1px 1px rgba(0, 0, 0, 0.04); + border-radius: 12px; + width: 100%; + padding: 0 0.5em; +} + +.profile-details-list-item { + padding: 0.5em 0.75em; + border-bottom: 1px solid #cec4c4; + display: flex; + justify-content: space-between; + align-items: center; +} + +.profile-details-border-none { + border: none; +} + +.profile-details-name { + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 500; + font-size: 14px; + line-height: 150%; + color: #585b61; + width: 30%; + text-align: left; + word-wrap: break-word; +} + +.profile-details-old-data { + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 400; + font-size: 14px; + line-height: 150%; + color: #c81e1e; + width: 30%; + text-align: center; + word-wrap: break-word; +} + +.profile-details-new-data { + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 400; + font-size: 14px; + line-height: 150%; + color: #046c4e; + width: 30%; + text-align: right; + word-wrap: break-word; +} + +.profile-details-data { + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 400; + font-size: 14px; + line-height: 150%; + color: #233876; +} + +#toast { + position: fixed; + top: 20px; + right: -300px; + color: #fff; + padding: 15px; + border-radius: 5px; +} + +.animated_toast { + animation: slideIn 0.5s ease-in-out forwards, + slideOut 0.5s ease-in-out 2.5s forwards; +} + +.success { + background: green; +} + +.failure { + background: #f43030; +} + +.hidden { + visibility: collapse; +} + +.disable-button { + opacity: 0.2; +} + +@keyframes slideIn { + from { + right: -300px; + } + + to { + right: 20px; + } +} + +@keyframes slideOut { + from { + right: 20px; + } + + to { + right: -300px; + } +} diff --git a/profile-diffs/assets/search.svg b/profile-diffs/assets/search.svg new file mode 100644 index 00000000..af3d86d4 --- /dev/null +++ b/profile-diffs/assets/search.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/profile-diffs/assets/sort-asc.svg b/profile-diffs/assets/sort-asc.svg new file mode 100644 index 00000000..8c3e2d8e --- /dev/null +++ b/profile-diffs/assets/sort-asc.svg @@ -0,0 +1,4 @@ + + + + diff --git a/profile-diffs/assets/sort-desc.svg b/profile-diffs/assets/sort-desc.svg new file mode 100644 index 00000000..0302f6e0 --- /dev/null +++ b/profile-diffs/assets/sort-desc.svg @@ -0,0 +1,4 @@ + + + + diff --git a/profile-diffs/constants.js b/profile-diffs/constants.js new file mode 100644 index 00000000..335d1c2f --- /dev/null +++ b/profile-diffs/constants.js @@ -0,0 +1,19 @@ +const SORT_BUTTON = '.sort-button'; +const SORT_ASC_ICON = 'asc-sort-icon'; +const SORT_DESC_ICON = 'desc-sort-icon'; +const DEFAULT_PAGE_SIZE = 10; +const OLDEST_FIRST = 'Oldest first'; +const NEWEST_FIRST = 'Newest first'; +const SEARCH_ELEMENT = 'assignee-search'; +const LAST_ELEMENT_CONTAINER = '.virtual'; + +const Status = { + APPROVED: 'APPROVED', + PENDING: 'PENDING', + NOT_APPROVED: 'NOT APPROVED', +}; + +const Order = { + DESCENDING: 'desc', + ASCENDING: 'asc', +}; diff --git a/profile-diffs/index.html b/profile-diffs/index.html new file mode 100644 index 00000000..2c87206d --- /dev/null +++ b/profile-diffs/index.html @@ -0,0 +1,60 @@ + + + + + + + Profile Diffs + + + +
Profile Difference Requests
+ +
+ +
+ + + +
+
+
+
+
+
+ + + + + + + + diff --git a/profile-diffs/local-utils.js b/profile-diffs/local-utils.js new file mode 100644 index 00000000..86fff6e8 --- /dev/null +++ b/profile-diffs/local-utils.js @@ -0,0 +1,53 @@ +// Utility functions +const parseProfileDiffParams = (uri, nextPageParamsObject) => { + const urlSearchParams = new URLSearchParams(uri); + for (const [key, value] of urlSearchParams.entries()) { + nextPageParamsObject[key] = value; + } + return nextPageParamsObject; +}; + +const generateProfileDiffsParams = (nextPageParams, forApi = true) => { + const urlSearchParams = new URLSearchParams(); + for (const [key, value] of Object.entries(nextPageParams)) { + if (!value) continue; + urlSearchParams.append(key, value); + } + return `/${ + forApi ? 'profileDiffs' : 'profile-diffs' + }?${urlSearchParams.toString()}`; +}; + +const getProfileDiffs = async (query = {}, nextLink) => { + const finalUrl = + API_BASE_URL + (nextLink || generateProfileDiffsParams(query)); + const res = await fetch(finalUrl, { + credentials: 'include', + method: 'GET', + headers: { + 'Content-type': 'application/json', + }, + }); + if (res.status === 401) { + return { notAuthorized: true }; + } + return await res.json(); +}; + +const users = {}; + +const getUser = async (userId) => { + if (users[userId]) { + return users[userId]; + } + const userResponse = await fetch(`${API_BASE_URL}/users?id=${userId}`, { + method: 'GET', + credentials: 'include', + headers: { + 'Content-type': 'application/json', + }, + }); + const { user } = await userResponse.json(); + users[userId] = user; + return user; +}; diff --git a/profile-diffs/script.js b/profile-diffs/script.js new file mode 100644 index 00000000..3e583c92 --- /dev/null +++ b/profile-diffs/script.js @@ -0,0 +1,298 @@ +let currentUserDetails; +const filterStates = {}; +const container = document.querySelector('.container'); +const sortButton = document.querySelector(SORT_BUTTON); +const ascIcon = document.getElementById(SORT_ASC_ICON); +const descIcon = document.getElementById(SORT_DESC_ICON); +const filterButtons = document.querySelectorAll('#filter-button'); +const profileDiffsContainer = document.querySelector('.profile-diffs'); +const searchElement = document.getElementById(SEARCH_ELEMENT); +const lastElementContainer = document.querySelector(LAST_ELEMENT_CONTAINER); +let nextLink = ''; +let isDataLoading = false; + +const toast = document.getElementById('toast'); + +function showToast({ message, type }) { + toast.innerText = message; + + if (type === 'success') { + toast.classList.add('success'); + toast.classList.remove('failure'); + } else { + toast.classList.add('failure'); + toast.classList.remove('success'); + } + + toast.classList.remove('hidden'); + toast.classList.add('animated_toast'); + + setTimeout(() => { + toast.classList.add('hidden'); + toast.classList.remove('animated_toast'); + }, 3000); +} + +const addTooltipToSortButton = () => { + const sortToolTip = createElement({ + type: 'span', + attributes: { class: 'tooltip sort-button-tooltip' }, + innerText: + filterStates.order === Order.ASCENDING ? OLDEST_FIRST : NEWEST_FIRST, + }); + sortButton.appendChild(sortToolTip); +}; + +function toggleStatusButton(statusValue) { + if (!statusValue) return; + filterButtons.forEach((filterButton) => { + filterButton.classList.toggle( + 'selected', + filterButton.name === statusValue, + ); + }); +} + +const updateUrl = () => { + if (history.pushState) { + window.history.pushState( + null, + '', + `${window.location.protocol}//${ + window.location.host + }${generateProfileDiffsParams(filterStates, false)}`, + ); + } +}; + +const updateUIBasedOnFilterStates = () => { + if (filterStates.order === 'asc') { + descIcon.style.display = 'none'; + ascIcon.style.display = 'block'; + } else { + ascIcon.style.display = 'none'; + descIcon.style.display = 'block'; + } + toggleStatusButton(filterStates.status); + searchElement.value = filterStates.username; +}; + +const render = async () => { + if (window.location.search) { + parseProfileDiffParams(window.location.search, filterStates); + filterStates.order ||= Order.DESCENDING; + filterStates.username ||= ''; + } else { + Object.assign(filterStates, { + status: Status.PENDING, + order: Order.DESCENDING, + size: DEFAULT_PAGE_SIZE, + username: '', + }); + } + addTooltipToSortButton(); + updateUIBasedOnFilterStates(); + changeFilter(); + updateUrl(); + await populateProfileDiffs(filterStates); + addIntersectionObserver(); +}; + +const changeFilter = () => { + nextLink = ''; + profileDiffsContainer.innerHTML = ''; +}; + +let profileDiffsListElement; + +async function populateProfileDiffs(query = {}, newLink) { + try { + isDataLoading = true; + const profileDiffsElement = document.getElementById('profile-diffs'); + if (!newLink) profileDiffsElement.innerHTML = ''; + const profileDiffs = await getProfileDiffs(query, newLink); + if (profileDiffs?.notAuthorized) { + profileDiffsElement.innerHTML = 'You are not AUTHORIZED!'; + return; + } + nextLink = profileDiffs.next; + const allProfileDiffs = profileDiffs.profileDiffs; + + if (!newLink) { + if (allProfileDiffs.length === 0) { + profileDiffsElement.innerHTML = 'No Data found!'; + return; + } + profileDiffsElement.innerHTML = ''; + profileDiffsListElement = createElement({ + type: 'div', + attributes: { class: 'profileDiffs__list-container' }, + }); + } + profileDiffsElement.appendChild(profileDiffsListElement); + for (let data of allProfileDiffs) { + await createProfileDiffCard(data, profileDiffsListElement); + } + } catch (error) { + showToast({ type: 'error', message: 'Something went wrong!' }); + } finally { + isDataLoading = false; + } +} + +const updateFilterStates = (key, value) => { + filterStates[key] = value; +}; + +const toggleSortIconAndOrder = () => { + const tooltip = sortButton.querySelector('.tooltip'); + const isAscending = filterStates.order === Order.ASCENDING; + + tooltip.textContent = isAscending ? NEWEST_FIRST : OLDEST_FIRST; + ascIcon.style.display = isAscending ? 'block' : 'none'; + descIcon.style.display = isAscending ? 'none' : 'block'; + + updateFilterStates('order', isAscending ? Order.DESCENDING : Order.ASCENDING); + updateUrl(); +}; + +const changeStatus = (status) => { + updateFilterStates('status', status); + updateUrl(); +}; + +const changeUsername = (username) => { + updateFilterStates('username', username); + updateUrl(); +}; + +function debounce(func, delay) { + let timerId; + return (...args) => { + clearTimeout(timerId); + timerId = setTimeout(() => func(...args), delay); + }; +} + +async function createProfileDiffCard(data, profileDiffCardList) { + const time = data.timestamp; + const fireBaseTime = new Date( + time._seconds * 1000 + time._nanoseconds / 1000000, + ); + const date = new Intl.DateTimeFormat('en-GB', { + day: '2-digit', + month: 'short', + year: '2-digit', + }).format(fireBaseTime); + const formattedTime = new Intl.DateTimeFormat('en-US', { + hour: 'numeric', + minute: 'numeric', + hour12: true, + }).format(fireBaseTime); + + const profileCard = createElement({ + type: 'div', + attributes: { class: 'profile-card' }, + }); + if (filterStates.status === Status.PENDING) { + profileCard.style.cursor = 'pointer'; + profileCard.addEventListener('click', () => { + window.location.href = `/profile-diff/?id=${data.id}`; + }); + } + profileDiffCardList.appendChild(profileCard); + + const profileCardLeft = createElement({ + type: 'div', + attributes: { class: 'profile shimmer' }, + }); + const profileCardPhoto = createElement({ + type: 'div', + attributes: { class: 'profile-pic' }, + }); + const profileCardInfo = createElement({ + type: 'div', + attributes: { class: 'profile-info' }, + }); + const profileCardName = createElement({ + type: 'div', + attributes: { class: 'profile-name-shimmer' }, + }); + const profileCardUsername = createElement({ + type: 'div', + attributes: { class: 'profile-username-shimmer' }, + }); + + profileCardInfo.appendChild(profileCardName); + profileCardInfo.appendChild(profileCardUsername); + profileCardLeft.appendChild(profileCardPhoto); + profileCardLeft.appendChild(profileCardInfo); + profileCard.appendChild(profileCardLeft); + + const profileCardRight = createElement({ + type: 'div', + attributes: { class: 'profile-card_right' }, + }); + const profileCardRightDate = createElement({ + type: 'span', + attributes: { class: 'profile-card_right-date-time' }, + innerText: `${date}`, + }); + const profileCardRightTime = createElement({ + type: 'span', + attributes: { class: 'profile-card_right-date-time' }, + innerText: `${formattedTime.toLowerCase()}`, + }); + profileCardRight.appendChild(profileCardRightDate); + profileCardRight.appendChild(profileCardRightTime); + profileCard.appendChild(profileCardLeft); + profileCard.appendChild(profileCardRight); + + const user = await getUser(data.userId); + profileCardLeft.classList.remove('shimmer'); + + profileCardPhoto.style.backgroundImage = `url(${user.picture?.url})`; + profileCardPhoto.style.backgroundSize = 'cover'; + + profileCardName.classList.remove('profile-name-shimmer'); + profileCardName.classList.add('profile-name'); + profileCardName.textContent = `${user.first_name} ${user.last_name}`; + + profileCardUsername.classList.remove('profile-username-shimmer'); + profileCardUsername.classList.add('profile-username'); + profileCardUsername.textContent = `${user.username}`; +} + +const addIntersectionObserver = () => { + intersectionObserver.observe(lastElementContainer); +}; + +const intersectionObserver = new IntersectionObserver(async (entries) => { + if (entries[0].isIntersecting && !isDataLoading && nextLink) { + await populateProfileDiffs({}, nextLink); + } +}); + +render(); + +sortButton.addEventListener('click', async () => { + toggleSortIconAndOrder(); + changeFilter(); + await populateProfileDiffs(filterStates); +}); + +searchElement.addEventListener( + 'input', + debounce(async (event) => { + changeUsername(event.target.value); + await populateProfileDiffs(filterStates); + }, 500), +); + +filterButtons.forEach((filterButton) => { + filterButton.addEventListener('click', async (event) => { + toggleStatusButton(filterButton.name); + changeStatus(filterButton.name); + await populateProfileDiffs(filterStates); + }); +}); diff --git a/profile-diffs/style.css b/profile-diffs/style.css new file mode 100644 index 00000000..6fed21ba --- /dev/null +++ b/profile-diffs/style.css @@ -0,0 +1,359 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'); + +:root { + --blue-color: #1d1283; + --blue-hover-color: #11085c; + --dark-blue: #1b1378; + --light-aqua: #d4f9f2; + --scandal: #e5fcf5; + --green-transparent: rgba(0, 255, 0, 0.2); + --green-color: green; + --red-transparent: rgba(255, 0, 0, 0.145); + --white: #ffffff; + --black-transparent: #000000a8; + --black: #181717; + --light-gray: #d9d9d9; + --razzmatazz: #df0057; + --red-color: red; + --gray: #808080; + --button-proceed: #008000; + --modal-color: #00000048; + --black-color: black; + --light-gray-color: lightgray; + --green10: #e1f9f1; + --green500: #19805e; + --secondary10: #fff0f6; + --secondary600: #b6004e; + --medium-gray: #aeaeae; + --dark-gray: #737373; + --blue-color-heading: #041187; + --white-gray: #f2f2f3; + --color-red: #ae1820; + --color-green: rgba(0, 128, 0, 0.8); + --color-warn: rgba(199, 129, 18, 0.8); +} + +*, +::after, +::before { + box-sizing: border-box; +} + +.header { + height: 7.25em; + background-color: #233876; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + font-family: 'Inter', sans-serif; + font-optical-sizing: auto; + font-weight: 500; + font-style: normal; + font-size: 20px; + color: var(--white); +} + +body { + font-family: 'Inter', sans-serif; + font-style: normal; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + min-height: 100vh; + user-select: none; + max-width: 100vw; + background-color: #f8fafd; +} + +.search-filter { + display: flex; + flex-direction: column; + align-items: center; + flex-wrap: wrap; + width: 100%; + padding: 1rem 0; + gap: 1rem; +} + +#search { + width: 90%; + max-width: 70rem; + display: flex; + justify-content: center; + align-items: center; + position: relative; +} + +#assignee-search { + width: 100%; + padding: 0.7rem 2.7rem 0.7rem 3.243rem; + border: 1px solid #fff; + box-shadow: 2px 1px 5px 0px #d4cccc40; + font-family: 'Inter', sans-serif; + font-optical-sizing: auto; + font-weight: 400; + font-style: normal; + font-size: 16px; + background-color: #fff; + height: 3.5rem; + color: var(--black-color); +} + +#assignee-search::placeholder { + color: #212429; +} + +#filter-container { + display: flex; + width: 90%; + max-width: 70rem; + justify-content: space-around; +} + +.search-icon { + position: absolute; + left: 0.7rem; +} + +#desc-sort-icon { + display: none; +} + +.sort-button { + padding: 8px; + height: 2.5rem; + cursor: pointer; + background-color: transparent; + border: none; + right: 0.7em; +} + +.tooltip-container { + position: relative; +} + +.sort-button-position { + position: absolute; +} + +.filter-button { + background-color: transparent; + color: #90959f; + font-family: 'Inter', sans-serif; + font-optical-sizing: auto; + font-weight: 600; + font-style: normal; + font-size: 16px; + border: none; + cursor: pointer; +} + +.filter-button:hover { + color: #233876; + text-decoration: underline; + text-underline-position: under; +} + +.selected { + color: #233876; + text-decoration: underline; + text-underline-position: under; +} + +.profile-diffs { + display: flex; + justify-content: center; +} + +.profileDiffs__list-container { + display: flex; + width: 90%; + max-width: 70rem; + flex-direction: column; + overflow: hidden; + border-radius: 10px; + background-color: white; + margin-bottom: 1em; +} + +.profile-card { + padding: 1em 1em 1em 0.5em; + border-bottom: 1px solid #eae8e8; + display: flex; + justify-content: space-between; +} + +.profile-card_right { + display: flex; + flex-direction: column; + align-items: end; +} + +.profile-card_right-date-time { + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 500; + font-size: 13px; + line-height: 150%; + color: #90959f; +} + +.profile { + display: flex; + align-items: center; +} + +.profile-pic { + width: 40px; + height: 40px; + border-radius: 50%; + background-color: #ccc; + margin-right: 10px; +} + +.profile-info { + display: flex; + flex-direction: column; +} + +.profile-name { + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 500; + font-size: 16px; + line-height: 150%; + color: #111928; +} + +.profile-username { + font-family: 'Inter', sans-serif; + font-style: normal; + font-weight: 300; + font-size: 13px; + line-height: 150%; + color: #111928; +} + +.profile-name-shimmer, +.profile-username-shimmer { + width: 100px; + height: 10px; + background-color: #ccc; + margin-bottom: 5px; +} + +.profile.shimmer .profile-pic, +.profile.shimmer .profile-name-shimmer, +.profile.shimmer .profile-username-shimmer { + background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%); + background-size: 1000px 100%; + animation: shimmer 1.5s infinite linear; +} + +@keyframes shimmer { + 0% { + background-position: -1000px 0; + } + 100% { + background-position: 1000px 0; + } +} + +.tooltip { + background-color: var(--black-color); + color: var(--white); + visibility: hidden; + text-align: center; + border-radius: 4px; + padding: 0.5rem; + position: absolute; + opacity: 0.9; + font-size: 0.7rem; + width: 10rem; + bottom: 100%; + left: 50%; + margin-left: -5rem; +} + +.sort-button-tooltip { + bottom: 120%; + width: 7rem; + margin-left: -5.8rem; +} + +.tooltip-container:hover .tooltip { + visibility: visible; + transition-delay: 400ms; +} + +.tooltip-container:hover .sort-button-tooltip { + visibility: visible; + transition-delay: 200ms; +} + +/* Loader Container */ +.loader-text { + text-align: center; + font-size: 1.5rem; +} + +.loader { + margin: auto auto; +} + +.loader p { + font-weight: 600; + font-size: 2em; +} + +#toast { + position: fixed; + top: 20px; + right: -300px; + color: #fff; + padding: 15px; + border-radius: 5px; +} + +.animated_toast { + animation: slideIn 0.5s ease-in-out forwards, + slideOut 0.5s ease-in-out 2.5s forwards; +} + +.success { + background: green; +} + +.failure { + background: #f43030; +} + +.hidden { + visibility: collapse; +} + +.disable-button { + opacity: 0.2; +} + +@keyframes slideIn { + from { + right: -300px; + } + + to { + right: 20px; + } +} + +@keyframes slideOut { + from { + right: 20px; + } + + to { + right: -300px; + } +} From 6d06e96e708360fff325f1efd399294184938445 Mon Sep 17 00:00:00 2001 From: Lakshay Manchanda Date: Mon, 23 Sep 2024 23:37:15 +0530 Subject: [PATCH 2/8] Error handeling --- index.html | 11 ++++++++--- profile-diffs/script.js | 5 ++++- script.js | 4 ++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 5d38c77b..b473a0bf 100644 --- a/index.html +++ b/index.html @@ -86,9 +86,7 @@ Create Goals Create Tasks - - Profile Update Requests - + Profile Diff Identity Service Logs + + Profile Update Requests + { + window.location.href = '/index.html'; + }, 3000); return; } nextLink = profileDiffs.next; diff --git a/script.js b/script.js index 034a2253..7bfc24cb 100644 --- a/script.js +++ b/script.js @@ -103,6 +103,9 @@ const repoSyncButton = document.getElementById('repo-sync-button'); const createActivityFeedButton = document.getElementById( 'create-activity-feed', ); +const profileUpdateRequestsButton = document.getElementById( + 'profile-update-requests', +); const requestPageButton = document.getElementById('requests-link'); const toast = document.getElementById('toast'); if (params.get('dev') === 'true') { @@ -110,6 +113,7 @@ if (params.get('dev') === 'true') { repoSyncDiv.classList.remove('element-display-remove'); createActivityFeedButton.classList.remove('element-display-remove'); requestPageButton.classList.remove('element-display-remove'); + profileUpdateRequestsButton.classList.remove('element-display-remove'); } function addClickEventListener( From 16a8c2f0efc9dd60a4e30e3d175b92c4fcb37713 Mon Sep 17 00:00:00 2001 From: Lakshay Manchanda Date: Tue, 24 Sep 2024 00:29:22 +0530 Subject: [PATCH 3/8] Handle API behind feature flag --- profile-diffs/local-utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/profile-diffs/local-utils.js b/profile-diffs/local-utils.js index 86fff6e8..7dbbf8ea 100644 --- a/profile-diffs/local-utils.js +++ b/profile-diffs/local-utils.js @@ -20,7 +20,8 @@ const generateProfileDiffsParams = (nextPageParams, forApi = true) => { const getProfileDiffs = async (query = {}, nextLink) => { const finalUrl = - API_BASE_URL + (nextLink || generateProfileDiffsParams(query)); + API_BASE_URL + + (nextLink || generateProfileDiffsParams({ ...query, dev: true })); const res = await fetch(finalUrl, { credentials: 'include', method: 'GET', From ec5e99ece28a017f91c45e7ac0d9f3ea5701355d Mon Sep 17 00:00:00 2001 From: Lakshay Manchanda Date: Tue, 24 Sep 2024 00:33:50 +0530 Subject: [PATCH 4/8] Style changes --- profile-diff/style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/profile-diff/style.css b/profile-diff/style.css index 335f3261..5915c197 100644 --- a/profile-diff/style.css +++ b/profile-diff/style.css @@ -62,7 +62,7 @@ body { font-optical-sizing: auto; font-weight: 500; font-style: normal; - font-size: 20px; + font-size: 1.25em; color: var(--white); position: relative; } @@ -70,7 +70,7 @@ body { .back { background-color: transparent; border: none; - padding: 10px; + padding: 0.625em; text-decoration: none; display: flex; align-items: center; From 8a571eea5ffa616d1ced7684250d151e11700f6a Mon Sep 17 00:00:00 2001 From: Lakshay Manchanda Date: Fri, 27 Sep 2024 03:52:02 +0530 Subject: [PATCH 5/8] Refactor filenames --- .../assets/left-arrow.svg | 0 .../constants.js | 0 .../index.html | 7 +++- .../profileDiffDetails.apiCalls.js | 40 ++++++++++++++++++ .../profileDiffDetails.utils.js | 41 ------------------- .../script.js | 0 .../style.css | 0 profile-diffs/index.html | 7 +++- ...ocal-utils.js => profileDiffs.apiCalls.js} | 20 --------- profile-diffs/profileDiffs.utils.js | 19 +++++++++ 10 files changed, 69 insertions(+), 65 deletions(-) rename {profile-diff => profile-diff-details}/assets/left-arrow.svg (100%) rename {profile-diff => profile-diff-details}/constants.js (100%) rename {profile-diff => profile-diff-details}/index.html (85%) create mode 100644 profile-diff-details/profileDiffDetails.apiCalls.js rename profile-diff/local-utils.js => profile-diff-details/profileDiffDetails.utils.js (51%) rename {profile-diff => profile-diff-details}/script.js (100%) rename {profile-diff => profile-diff-details}/style.css (100%) rename profile-diffs/{local-utils.js => profileDiffs.apiCalls.js} (56%) create mode 100644 profile-diffs/profileDiffs.utils.js diff --git a/profile-diff/assets/left-arrow.svg b/profile-diff-details/assets/left-arrow.svg similarity index 100% rename from profile-diff/assets/left-arrow.svg rename to profile-diff-details/assets/left-arrow.svg diff --git a/profile-diff/constants.js b/profile-diff-details/constants.js similarity index 100% rename from profile-diff/constants.js rename to profile-diff-details/constants.js diff --git a/profile-diff/index.html b/profile-diff-details/index.html similarity index 85% rename from profile-diff/index.html rename to profile-diff-details/index.html index 17487406..68217d83 100644 --- a/profile-diff/index.html +++ b/profile-diff-details/index.html @@ -20,10 +20,13 @@
+ - - + + + + diff --git a/profile-diff-details/profileDiffDetails.apiCalls.js b/profile-diff-details/profileDiffDetails.apiCalls.js new file mode 100644 index 00000000..df464055 --- /dev/null +++ b/profile-diff-details/profileDiffDetails.apiCalls.js @@ -0,0 +1,40 @@ +const getProfileDiff = async (id) => { + try { + const finalUrl = `${API_BASE_URL}/profileDiffs/${id}`; + const res = await fetch(finalUrl, { + credentials: 'include', + method: 'GET', + headers: { + 'Content-type': 'application/json', + }, + }); + if (res.status === 401) { + return { notAuthorized: true }; + } + if (res.status === 404) { + return { profileDiffExist: false }; + } + return { profileDiffExist: true, ...(await res.json()).profileDiff }; + } catch (err) { + throw err; + } +}; + +const fetchUser = async (userId) => { + try { + const userResponse = await fetch(`${API_BASE_URL}/users?id=${userId}`, { + method: 'GET', + credentials: 'include', + headers: { + 'Content-type': 'application/json', + }, + }); + if (userResponse.status === 404) { + return { userExist: false }; + } + const { user } = await userResponse.json(); + return { ...user, userExist: true }; + } catch (err) { + throw err; + } +}; diff --git a/profile-diff/local-utils.js b/profile-diff-details/profileDiffDetails.utils.js similarity index 51% rename from profile-diff/local-utils.js rename to profile-diff-details/profileDiffDetails.utils.js index 64aaff40..d6cfd1ec 100644 --- a/profile-diff/local-utils.js +++ b/profile-diff-details/profileDiffDetails.utils.js @@ -1,44 +1,3 @@ -const getProfileDiff = async (id) => { - try { - const finalUrl = `${API_BASE_URL}/profileDiffs/${id}`; - const res = await fetch(finalUrl, { - credentials: 'include', - method: 'GET', - headers: { - 'Content-type': 'application/json', - }, - }); - if (res.status === 401) { - return { notAuthorized: true }; - } - if (res.status === 404) { - return { profileDiffExist: false }; - } - return { profileDiffExist: true, ...(await res.json()).profileDiff }; - } catch (err) { - throw err; - } -}; - -const fetchUser = async (userId) => { - try { - const userResponse = await fetch(`${API_BASE_URL}/users?id=${userId}`, { - method: 'GET', - credentials: 'include', - headers: { - 'Content-type': 'application/json', - }, - }); - if (userResponse.status === 404) { - return { userExist: false }; - } - const { user } = await userResponse.json(); - return { ...user, userExist: true }; - } catch (err) { - throw err; - } -}; - function getDataItem(data, itemName) { const item = data[itemName]; diff --git a/profile-diff/script.js b/profile-diff-details/script.js similarity index 100% rename from profile-diff/script.js rename to profile-diff-details/script.js diff --git a/profile-diff/style.css b/profile-diff-details/style.css similarity index 100% rename from profile-diff/style.css rename to profile-diff-details/style.css diff --git a/profile-diffs/index.html b/profile-diffs/index.html index 2c87206d..4d4a0536 100644 --- a/profile-diffs/index.html +++ b/profile-diffs/index.html @@ -50,11 +50,14 @@
+ - - + + + + diff --git a/profile-diffs/local-utils.js b/profile-diffs/profileDiffs.apiCalls.js similarity index 56% rename from profile-diffs/local-utils.js rename to profile-diffs/profileDiffs.apiCalls.js index 7dbbf8ea..5a4bb0fc 100644 --- a/profile-diffs/local-utils.js +++ b/profile-diffs/profileDiffs.apiCalls.js @@ -1,23 +1,3 @@ -// Utility functions -const parseProfileDiffParams = (uri, nextPageParamsObject) => { - const urlSearchParams = new URLSearchParams(uri); - for (const [key, value] of urlSearchParams.entries()) { - nextPageParamsObject[key] = value; - } - return nextPageParamsObject; -}; - -const generateProfileDiffsParams = (nextPageParams, forApi = true) => { - const urlSearchParams = new URLSearchParams(); - for (const [key, value] of Object.entries(nextPageParams)) { - if (!value) continue; - urlSearchParams.append(key, value); - } - return `/${ - forApi ? 'profileDiffs' : 'profile-diffs' - }?${urlSearchParams.toString()}`; -}; - const getProfileDiffs = async (query = {}, nextLink) => { const finalUrl = API_BASE_URL + diff --git a/profile-diffs/profileDiffs.utils.js b/profile-diffs/profileDiffs.utils.js new file mode 100644 index 00000000..1155f8a6 --- /dev/null +++ b/profile-diffs/profileDiffs.utils.js @@ -0,0 +1,19 @@ +// Utility functions +const parseProfileDiffParams = (uri, nextPageParamsObject) => { + const urlSearchParams = new URLSearchParams(uri); + for (const [key, value] of urlSearchParams.entries()) { + nextPageParamsObject[key] = value; + } + return nextPageParamsObject; +}; + +const generateProfileDiffsParams = (nextPageParams, forApi = true) => { + const urlSearchParams = new URLSearchParams(); + for (const [key, value] of Object.entries(nextPageParams)) { + if (!value) continue; + urlSearchParams.append(key, value); + } + return `/${ + forApi ? 'profileDiffs' : 'profile-diffs' + }?${urlSearchParams.toString()}`; +}; From 2995f6629fc39671924fa7adf9ff04b3e94d87bd Mon Sep 17 00:00:00 2001 From: Lakshay Manchanda Date: Fri, 27 Sep 2024 04:06:43 +0530 Subject: [PATCH 6/8] Refactored some code --- profile-diff-details/profileDiffDetails.utils.js | 9 ++++----- profile-diff-details/style.css | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/profile-diff-details/profileDiffDetails.utils.js b/profile-diff-details/profileDiffDetails.utils.js index d6cfd1ec..e6096ff5 100644 --- a/profile-diff-details/profileDiffDetails.utils.js +++ b/profile-diff-details/profileDiffDetails.utils.js @@ -1,12 +1,11 @@ -function getDataItem(data, itemName) { +function getUserDataItem(data, itemName) { const item = data[itemName]; - if (item) { + if (item || (itemName === YEARS_OF_EXPERIENCE && item === 0)) { return item; - } else { - if (itemName === YEARS_OF_EXPERIENCE && item === 0) return item; - else return ''; } + + return ''; } function checkDifferentValues(primaryData, secondaryData) { diff --git a/profile-diff-details/style.css b/profile-diff-details/style.css index 5915c197..2fd4349b 100644 --- a/profile-diff-details/style.css +++ b/profile-diff-details/style.css @@ -208,7 +208,7 @@ body { --_g: no-repeat radial-gradient(circle closest-side, #000 90%, #0000); background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%; background-size: calc(100% / 3) 50%; - animation: l3 1s infinite linear; + animation: loader-animation 1s infinite linear; } .button__loader { @@ -217,10 +217,10 @@ body { --_g: no-repeat radial-gradient(circle closest-side, #fff 90%, #0000); background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%; background-size: calc(100% / 3) 50%; - animation: l3 1s infinite linear; + animation: loader-animation 1s infinite linear; } -@keyframes l3 { +@keyframes loader-animation { 20% { background-position: 0% 0%, 50% 50%, 100% 50%; } From 9343fbbbcb290cfbbe505ebb1a3cba83ad3dd2c4 Mon Sep 17 00:00:00 2001 From: Lakshay Manchanda Date: Fri, 27 Sep 2024 04:29:44 +0530 Subject: [PATCH 7/8] Renamed --- profile-diff-details/index.html | 10 +++++----- profile-diff-details/profileDiffDetails.utils.js | 4 ++-- profile-diffs/script.js | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/profile-diff-details/index.html b/profile-diff-details/index.html index 68217d83..9df40dd4 100644 --- a/profile-diff-details/index.html +++ b/profile-diff-details/index.html @@ -3,7 +3,7 @@ - + - - - - + + + + diff --git a/profile-diff-details/profileDiffDetails.utils.js b/profile-diff-details/profileDiffDetails.utils.js index e6096ff5..939b8cc4 100644 --- a/profile-diff-details/profileDiffDetails.utils.js +++ b/profile-diff-details/profileDiffDetails.utils.js @@ -12,8 +12,8 @@ function checkDifferentValues(primaryData, secondaryData) { const diffValues = new Set(); for (const listItem in primaryData) { - const oldValue = getDataItem(primaryData, listItem); - const newValue = getDataItem(secondaryData, listItem); + const oldValue = getUserDataItem(primaryData, listItem); + const newValue = getUserDataItem(secondaryData, listItem); const isValueEqual = String(oldValue).trim() === String(newValue).trim(); if (!isValueEqual) { diff --git a/profile-diffs/script.js b/profile-diffs/script.js index 198e6648..513c5150 100644 --- a/profile-diffs/script.js +++ b/profile-diffs/script.js @@ -200,7 +200,7 @@ async function createProfileDiffCard(data, profileDiffCardList) { if (filterStates.status === Status.PENDING) { profileCard.style.cursor = 'pointer'; profileCard.addEventListener('click', () => { - window.location.href = `/profile-diff/?id=${data.id}`; + window.location.href = `/profile-diff-details/?id=${data.id}`; }); } profileDiffCardList.appendChild(profileCard); From b3ea4395087297ebf5cec2b400d24699d8f3240e Mon Sep 17 00:00:00 2001 From: Lakshay Manchanda Date: Sat, 28 Sep 2024 13:01:19 +0530 Subject: [PATCH 8/8] Refactored css and added css variables --- profile-diff-details/constants.js | 8 ++++---- profile-diff-details/style.css | 15 ++------------ profile-diffs/constants.js | 8 ++++---- profile-diffs/style.css | 33 +++++++++++++------------------ 4 files changed, 24 insertions(+), 40 deletions(-) diff --git a/profile-diff-details/constants.js b/profile-diff-details/constants.js index 0342e1af..767a36b8 100644 --- a/profile-diff-details/constants.js +++ b/profile-diff-details/constants.js @@ -1,6 +1,6 @@ const YEARS_OF_EXPERIENCE = 'yoe'; -const fieldDisplayName = { +const fieldDisplayName = Object.freeze({ first_name: 'First name', last_name: 'Last name', designation: 'Role', @@ -13,10 +13,10 @@ const fieldDisplayName = { twitter_id: 'Twitter', instagram_id: 'Instagram', website: 'Website', -}; +}); -const Status = { +const Status = Object.freeze({ APPROVED: 'APPROVED', PENDING: 'PENDING', NOT_APPROVED: 'NOT APPROVED', -}; +}); diff --git a/profile-diff-details/style.css b/profile-diff-details/style.css index 2fd4349b..51b28e30 100644 --- a/profile-diff-details/style.css +++ b/profile-diff-details/style.css @@ -31,6 +31,7 @@ --color-red: #ae1820; --color-green: rgba(0, 128, 0, 0.8); --color-warn: rgba(199, 129, 18, 0.8); + --font-family: 'Inter', sans-serif; } *, @@ -40,7 +41,7 @@ } body { - font-family: 'Roboto', sans-serif; + font-family: var(--font-family); margin: 0; padding: 0; display: flex; @@ -58,7 +59,6 @@ body { align-items: center; justify-content: center; text-align: center; - font-family: 'Inter', sans-serif; font-optical-sizing: auto; font-weight: 500; font-style: normal; @@ -89,7 +89,6 @@ body { flex-direction: column; align-items: center; gap: 1em; - font-family: 'Inter', sans-serif; font-weight: 700; font-size: x-large; text-align: center; @@ -102,7 +101,6 @@ body { } .user_name { - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 500; font-size: 20px; @@ -118,7 +116,6 @@ body { justify-content: end; align-items: center; color: #233876; - font-family: 'Inter', sans-serif; font-weight: 400; font-size: 14px; } @@ -133,7 +130,6 @@ body { } .reason_heading { - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 500; font-size: 17px; @@ -146,7 +142,6 @@ body { } .reason_textarea { - font-family: 'Inter', sans-serif; font-style: normal; font-size: 16px; background: #ffffff; @@ -171,7 +166,6 @@ body { background: #046c4e; border-radius: 10px; border: none; - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 500; font-size: 18px; @@ -189,7 +183,6 @@ body { background: #c81e1e; border-radius: 10px; border: none; - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 500; font-size: 18px; @@ -257,7 +250,6 @@ body { } .profile-details-name { - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 500; font-size: 14px; @@ -269,7 +261,6 @@ body { } .profile-details-old-data { - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 400; font-size: 14px; @@ -281,7 +272,6 @@ body { } .profile-details-new-data { - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 400; font-size: 14px; @@ -293,7 +283,6 @@ body { } .profile-details-data { - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 400; font-size: 14px; diff --git a/profile-diffs/constants.js b/profile-diffs/constants.js index 335d1c2f..19a931c7 100644 --- a/profile-diffs/constants.js +++ b/profile-diffs/constants.js @@ -7,13 +7,13 @@ const NEWEST_FIRST = 'Newest first'; const SEARCH_ELEMENT = 'assignee-search'; const LAST_ELEMENT_CONTAINER = '.virtual'; -const Status = { +const Status = Object.freeze({ APPROVED: 'APPROVED', PENDING: 'PENDING', NOT_APPROVED: 'NOT APPROVED', -}; +}); -const Order = { +const Order = Object.freeze({ DESCENDING: 'desc', ASCENDING: 'asc', -}; +}); diff --git a/profile-diffs/style.css b/profile-diffs/style.css index 6fed21ba..97120341 100644 --- a/profile-diffs/style.css +++ b/profile-diffs/style.css @@ -31,6 +31,7 @@ --color-red: #ae1820; --color-green: rgba(0, 128, 0, 0.8); --color-warn: rgba(199, 129, 18, 0.8); + --font-family: 'Inter', sans-serif; } *, @@ -39,6 +40,19 @@ box-sizing: border-box; } +body { + font-family: var(--font-family); + font-style: normal; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + min-height: 100vh; + user-select: none; + max-width: 100vw; + background-color: #f8fafd; +} + .header { height: 7.25em; background-color: #233876; @@ -46,7 +60,6 @@ align-items: center; justify-content: center; text-align: center; - font-family: 'Inter', sans-serif; font-optical-sizing: auto; font-weight: 500; font-style: normal; @@ -54,19 +67,6 @@ color: var(--white); } -body { - font-family: 'Inter', sans-serif; - font-style: normal; - margin: 0; - padding: 0; - display: flex; - flex-direction: column; - min-height: 100vh; - user-select: none; - max-width: 100vw; - background-color: #f8fafd; -} - .search-filter { display: flex; flex-direction: column; @@ -91,7 +91,6 @@ body { padding: 0.7rem 2.7rem 0.7rem 3.243rem; border: 1px solid #fff; box-shadow: 2px 1px 5px 0px #d4cccc40; - font-family: 'Inter', sans-serif; font-optical-sizing: auto; font-weight: 400; font-style: normal; @@ -141,7 +140,6 @@ body { .filter-button { background-color: transparent; color: #90959f; - font-family: 'Inter', sans-serif; font-optical-sizing: auto; font-weight: 600; font-style: normal; @@ -192,7 +190,6 @@ body { } .profile-card_right-date-time { - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 500; font-size: 13px; @@ -219,7 +216,6 @@ body { } .profile-name { - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 500; font-size: 16px; @@ -228,7 +224,6 @@ body { } .profile-username { - font-family: 'Inter', sans-serif; font-style: normal; font-weight: 300; font-size: 13px;