diff --git a/constants.js b/constants.js index 7a88a01b..df4c3d84 100644 --- a/constants.js +++ b/constants.js @@ -1,6 +1,17 @@ const API_BASE_URL = 'https://api.realdevsquad.com'; const USER_MANAGEMENT_LINK = 'user-management-link'; const EXTENSION_REQUESTS_LINK = 'extension-requests-link'; +const SYNC_USERS_STATUS = 'sync-users-status'; +const SYNC_EXTERNAL_ACCOUNTS = 'sync-external-accounts'; +const SYNC_UNVERIFIED_USERS = 'sync-unverified-users'; +const SYNC_USERS_STATUS_UPDATE = 'sync-users-status-update'; +const SYNC_EXTERNAL_ACCOUNTS_UPDATE = 'sync-external-accounts-update'; +const SYNC_UNVERIFIED_USERS_UPDATE = 'sync-unverified-users-update'; +const SYNC_IN_PROGRESS = 'Last Sync: In progress'; +const SYNC_SUCCESSFUL = 'Last Sync: Successful'; +const SYNC_FAILED = 'Last Sync: Failed'; +const DISABLED = 'disabled'; + const dummyPicture = 'https://dashboard.realdevsquad.com/users/images/avatar.png'; const USER_MANAGEMENT_URL = diff --git a/index.html b/index.html index c5d836fb..88d48cf3 100644 --- a/index.html +++ b/index.html @@ -18,6 +18,32 @@ Tasks +
+
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
btn.classList.remove('element-display-remove'), ); + buttonSection.classList.remove('element-display-remove'); + syncUsersStatusUpdate.textContent = `Last Sync: ${ + localStorage.getItem('lastSyncUsersStatus') || + 'Synced Data Not Available' + }`; + syncExternalAccountsUpdate.textContent = `Last Sync: ${ + localStorage.getItem('lastSyncExternalAccounts') || + 'Synced Data Not Available' + }`; + syncUnverifiedUsersUpdate.textContent = `Last Sync: ${ + localStorage.getItem('lastSyncUnverifiedUsers') || + 'Synced Data Not Available' + }`; } } catch (err) { console.log(err); @@ -28,4 +60,82 @@ if (params.get('dev') === 'true') { createGoalButton.classList.remove('element-display-remove'); } -showUserManagementButton(); +function addClickEventListener( + button, + endpoint, + localStorageKey, + lastSyncElement, + method, +) { + button.addEventListener('click', async (event) => { + await handleSync(endpoint, localStorageKey, lastSyncElement, method, event); + }); +} + +async function handleSync( + endpoint, + localStorageKey, + lastSyncElement, + method, + event, +) { + const button = event.target; + const wrapper = button.parentElement; + const spinner = wrapper.querySelector('.spinner'); + const status = wrapper.querySelector('.status'); + + button.disabled = true; + button.classList.add(DISABLED); + spinner.style.display = 'inline-block'; + status.textContent = SYNC_IN_PROGRESS; + + try { + const response = await fetch(`${API_BASE_URL}${endpoint}`, { + method: method, + credentials: 'include', + }); + + if (response.ok) { + status.textContent = SYNC_SUCCESSFUL; + const lastSyncTimestamp = getCurrentTimestamp(); + + localStorage.setItem(localStorageKey, lastSyncTimestamp); + + if (lastSyncElement) { + lastSyncElement.textContent = `Last Sync: ${lastSyncTimestamp}`; + } + } else { + status.textContent = SYNC_FAILED; + } + } catch (err) { + console.error(err); + status.textContent = SYNC_FAILED; + } finally { + spinner.style.display = 'none'; + button.classList.remove(DISABLED); + button.disabled = false; + } +} + +// Attach (button,API,cookie name,div element of status,HTTP method of API +addClickEventListener( + syncUsersStatusButton, + '/users/status/update', + 'lastSyncUsersStatus', + syncUsersStatusUpdate, + 'PATCH', +); +addClickEventListener( + syncExternalAccountsButton, + '/external-accounts/discord-sync', + 'lastSyncExternalAccounts', + syncExternalAccountsUpdate, + 'PATCH', +); +addClickEventListener( + syncUnverifiedUsersButton, + '/users/', + 'lastSyncUnverifiedUsers', + syncUnverifiedUsersUpdate, + 'POST', +); diff --git a/style.css b/style.css index 36181d15..d6df8508 100644 --- a/style.css +++ b/style.css @@ -44,6 +44,7 @@ body { button { width: 250px; cursor: pointer; + position: relative; } .create-task-btn { @@ -179,3 +180,62 @@ footer { background-color: var(--blue-color); border: none; } + +#sync-buttons.element-display-remove { + display: none; +} + +#sync-buttons { + display: flex; + justify-content: center; + align-items: center; + gap: 20px; + margin-top: 50px; + margin-bottom: 20px; + padding: 0 100px; + flex-wrap: wrap; +} + +#sync-buttons .button-container { + flex: 1 1 100%; + max-width: 250px; + display: flex; + flex-direction: column; + align-items: center; +} +#sync-buttons .spinner { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + display: none; + width: 20px; + height: 20px; + border: 3px solid #f3f3f3; + border-top: 3px solid #1d1283; + border-radius: 50%; + animation: spin 1s linear infinite; +} + +#sync-buttons .status { + font-weight: bold; + margin-top: 10px; + text-align: center; + max-height: 20px; +} + +.action-button.disabled { + opacity: 0.5; + background-color: #1d1283; + color: #f3f3f3; + pointer-events: none; +} + +@keyframes spin { + 0% { + transform: translate(-50%, -50%) rotate(0deg); + } + 100% { + transform: translate(-50%, -50%) rotate(360deg); + } +}