diff --git a/__tests__/home/home.test.js b/__tests__/home/home.test.js index 6252da33..28713064 100644 --- a/__tests__/home/home.test.js +++ b/__tests__/home/home.test.js @@ -387,6 +387,57 @@ describe('Home Page', () => { expect(repoLinkStyle).toBeTruthy(); }); + it('Check user profile with dropdown options', async () => { + const DROPDOWN_OPTIONS = [ + { + name: 'Home', + link: 'https://dashboard.realdevsquad.com/', + }, + { + name: 'Status', + link: 'https://my.realdevsquad.com/', + }, + { + name: 'Profile', + link: 'https://my.realdevsquad.com/profile', + }, + { + name: 'Tasks', + link: 'https://my.realdevsquad.com/tasks', + }, + { + name: 'Identity', + link: 'https://my.realdevsquad.com/identity', + }, + ]; + + const userName = await page.$eval( + '#user-name', + (element) => element.textContent, + ); + const userImage = await page.$eval('#user-img', (element) => element.src); + expect(userName).toContain(superUserData.first_name); + expect(userImage).toEqual(superUserData.picture.url); + + const userInfoButton = await page.$('.user-info'); + await userInfoButton.click(); + + const hrefs = await page.$$eval( + '.dropdown-list .dropdown-item a', + (elements) => elements.map((element) => element.getAttribute('href')), + ); + + const expectedHrefs = DROPDOWN_OPTIONS.map((option) => option.link); + + expect(hrefs).toEqual(expectedHrefs); + + const signoutButton = await page.$('#signout-option'); + await signoutButton.click(); + const signinButton = await page.$('.sign-in-btn'); + + expect(signinButton).toBeTruthy(); + }); + it('should display the Sync Onboarding 31d+ button', async () => { const syncOnboarding31dPlusUsersButton = await page.$( '#sync-onboarding-31d-plus-users', diff --git a/constants.js b/constants.js index c705a139..e1a94da4 100644 --- a/constants.js +++ b/constants.js @@ -26,7 +26,6 @@ const DISABLED = 'disabled'; const STATUS_BASE_URL_PROD = 'https://status.realdevsquad.com'; const STATUS_BASE_URL_STAGING = 'https://staging-status.realdevsquad.com'; const STATUS_BASE_URL = STATUS_BASE_URL_PROD; - const dummyPicture = 'https://dashboard.realdevsquad.com/images/avatar.png'; const USER_MANAGEMENT_URL = 'https://dashboard.realdevsquad.com/users/details/?username='; diff --git a/index.html b/index.html index 985abe5b..d695df0c 100644 --- a/index.html +++ b/index.html @@ -37,9 +37,16 @@ Sign In With GitHub - + +
+ + + + +
+
diff --git a/mock-data/users/index.js b/mock-data/users/index.js index 44231e0c..85b94e0a 100644 --- a/mock-data/users/index.js +++ b/mock-data/users/index.js @@ -219,6 +219,10 @@ const superUserData = { twitter_id: 'Codesh_', first_name: 'Kotesh', username: 'kotesh', + picture: { + publicId: 'profile/w2XR9Gkid6Kg5xCJ5Elm/rzh3cwff7hh7srvg63mb', + url: 'https://res.cloudinary.com/realdevsquad/image/upload/v1692990078/profile/w2XR9Gkid6Kg5xCJ5Elm/rzh3cwff7hh7srvg63mb.png', + }, }; module.exports = { allUsersData, diff --git a/script.js b/script.js index fd75bf04..c289a513 100644 --- a/script.js +++ b/script.js @@ -338,6 +338,106 @@ addClickEventListener( syncNicknamesStatusUpdate, 'POST', ); + +const DROPDOWN_OPTIONS = [ + { + name: 'Home', + link: 'https://dashboard.realdevsquad.com/', + }, + { + name: 'Status', + link: 'https://my.realdevsquad.com/', + }, + { + name: 'Profile', + link: 'https://my.realdevsquad.com/profile', + }, + { + name: 'Tasks', + link: 'https://my.realdevsquad.com/tasks', + }, + { + name: 'Identity', + link: 'https://my.realdevsquad.com/identity', + }, +]; + +async function handleUserSignin() { + try { + const self_user = await getSelfUser(); + if (self_user) { + const signInButton = document.querySelector('.sign-in-btn'); + signInButton.style.display = 'none'; + const dropdown = document.getElementById('dropdown'); + const userInfo = document.querySelector('.user-info'); + const username = document.getElementById('user-name'); + const userImage = document.getElementById('user-img'); + + username.innerText = `Hello, ${self_user.first_name}!`; + userImage.setAttribute('src', self_user?.picture.url); + userInfo.classList.add('active'); + const dropdownList = createElement({ + type: 'ul', + attributes: { + class: 'dropdown-list', + }, + }); + + DROPDOWN_OPTIONS.forEach((option) => { + const listElement = createElement({ + type: 'li', + attributes: { + class: 'dropdown-item', + }, + }); + const anchorElement = createElement({ + type: 'a', + attributes: { + class: 'dropdown-link', + }, + }); + anchorElement.href = `${option.link}`; + anchorElement.innerText = `${option.name}`; + listElement.append(anchorElement); + dropdownList.append(listElement); + }); + const horizontalLine = createElement({ + type: 'hr', + attributes: { + class: 'line', + }, + }); + + dropdownList.append(horizontalLine); + const signOutElement = createElement({ + type: 'li', + attributes: { + class: 'dropdown-item', + id: 'signout-option', + }, + }); + signOutElement.classList.add('dropdown-link'); + + dropdownList.append(signOutElement); + signOutElement.innerText = 'Sign Out'; + dropdown.append(dropdownList); + + userInfo.addEventListener('click', () => { + if (dropdown.classList.contains('active')) { + dropdown.classList.remove('active'); + } else { + dropdown.classList.add('active'); + } + }); + + signOutElement.addEventListener('click', () => { + signout('/auth/signout'); + }); + } + } catch (error) {} +} +handleUserSignin(); + addClickEventListener( syncIdle7dUsersButton, '/discord-actions/group-idle-7d', diff --git a/style.css b/style.css index 780d69c8..2a68ea73 100644 --- a/style.css +++ b/style.css @@ -10,6 +10,8 @@ --blue-color: #1d1283; --success-color: green; --failure-color: #f44336; + --lightblue-color: #0d6efd; + --lightgray-color: #d7d6d6; } body { @@ -367,6 +369,77 @@ footer { .element-display-remove { display: none !important; } +/* Dropdown container */ + +#dropdown { + display: none; + position: absolute; + width: 9.5rem; + right: 1.5rem; + text-align: center; + top: 3rem; + z-index: 100; + flex-direction: column; + justify-content: center; + padding: 0.63rem 0; + background-color: var(--white-color); + border-radius: 0.63rem; + font-size: 0.75rem; + box-shadow: rgba(60, 64, 67, 0.3) 0 0.06rem 0.13rem 0, + rgba(60, 64, 67, 0.15) 0 0.13rem 0.38rem 0.13rem; +} + +#signout-option { + cursor: pointer; +} + +#dropdown.active { + display: flex; +} + +.dropdown-list { + list-style-type: none; + padding-left: 0; + margin-left: 0; + cursor: pointer; + color: var(--lightblue-color); + font-weight: 700; +} +.dropdown-item { + padding: 0.65rem 0; +} +.dropdown-item:hover { + background-color: var(--lightgray-color); + transition: background-color 0.31s ease-in-out; +} +.dropdown-link { + display: block; + width: 100%; + text-decoration: none; + color: var(--lightblue-color); +} + +.user-info { + display: none; + position: absolute; + align-items: center; + gap: 0.5rem; + cursor: pointer; + color: var(--white-color); + order: 3; + font-size: smaller; + font-weight: bold; +} +.user-info.active { + display: flex; + right: 0.5rem; +} + +.user-info img { + width: 1.75rem; + height: 1.75rem; + border-radius: 100%; +} /* MEDIA QUERY */ @@ -403,6 +476,9 @@ footer { .nav-links .links a { color: var(--blue-color); } + .user-info { + position: inherit; + } } @media only screen and (max-width: 600px) { @@ -412,4 +488,7 @@ footer { .action-button { text-align: center; } + .logo { + display: none; + } } diff --git a/utils.js b/utils.js index 706c2538..8253a155 100644 --- a/utils.js +++ b/utils.js @@ -1,15 +1,19 @@ -async function getSelfUser() { +async function getSelfUser(endpoint = '/users/self') { try { - const res = await fetch(`${API_BASE_URL}/users/self`, { + const res = await fetch(`${API_BASE_URL}${endpoint}`, { method: 'GET', credentials: 'include', headers: { 'Content-type': 'application/json', }, }); - const self_user = await res.json(); - if (res.status === 200) { - return self_user; + if (endpoint === '/users/self') { + const self_user = await res.json(); + if (res.status === 200) { + return self_user; + } + } else { + location.reload(); } } catch (err) {} } @@ -65,3 +69,15 @@ function debounce(func, delay) { async function addDelay(milliSeconds) { await new Promise((resolve) => setTimeout(resolve, milliSeconds)); } + +async function signout() { + try { + await fetch('https://api.realdevsquad.com/auth/signout', { + method: 'GET', + credentials: 'include', + }); + location.reload(); + } catch (error) { + console.error('Signout failed:', error); + } +}