Implementing new scoring system

This commit is contained in:
sairaj mote 2022-11-08 05:01:31 +05:30
parent 8e8b10c1a9
commit 7fcdf46618
7 changed files with 215 additions and 157 deletions

File diff suppressed because one or more lines are too long

View File

@ -72,9 +72,20 @@ body[data-theme=dark] ::-webkit-calendar-picker-indicator {
filter: invert(1); filter: invert(1);
} }
.calistoga { .overpass {
font-weight: 400; font-weight: 700;
font-family: "Calistoga", cursive; font-family: "Overpass", sans-serif;
}
h1,
h2,
h3,
h4,
h5,
h6 {
letter-spacing: -0.01em;
font-weight: 700;
font-family: "Overpass", sans-serif;
} }
p, p,
@ -284,10 +295,6 @@ cube-loader {
--size: 1.2rem; --size: 1.2rem;
} }
sm-form {
--gap: 1rem;
}
sm-select { sm-select {
--padding: 0.8rem; --padding: 0.8rem;
--min-width: fit-content; --min-width: fit-content;
@ -301,11 +308,11 @@ sm-option {
font-size: 0.9rem; font-size: 0.9rem;
} }
strip-select { sm-chips {
--gap: 0.3rem; --gap: 0.3rem;
} }
strip-option { sm-chip {
position: relative; position: relative;
font-size: 0.9rem; font-size: 0.9rem;
--border-radius: 0.3rem; --border-radius: 0.3rem;
@ -313,17 +320,6 @@ strip-option {
-moz-user-select: none; -moz-user-select: none;
user-select: none; user-select: none;
} }
sm-button {
--border-radius: 0.3rem;
}
sm-button[variant=primary] .icon {
fill: rgba(var(--background-color), 1);
}
sm-button[disabled] .icon {
fill: rgba(var(--text-color), 0.6);
}
ul { ul {
list-style: none; list-style: none;
} }
@ -698,7 +694,6 @@ ul {
} }
#confirmation_popup h4, #confirmation_popup h4,
#prompt_popup h4 { #prompt_popup h4 {
font-weight: 500;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
#confirmation_popup .flex, #confirmation_popup .flex,
@ -1119,10 +1114,6 @@ ul {
background-color: #00c853 !important; background-color: #00c853 !important;
} }
.task-title {
font-weight: 500;
}
.padding { .padding {
padding: 1rem; padding: 1rem;
} }
@ -1135,14 +1126,11 @@ ul {
} }
#dashboard_view_selector { #dashboard_view_selector {
border-radius: 2rem; border-radius: 0.5rem;
margin: 0 auto; margin: 0 auto;
padding: 0.3rem; padding: 0.3rem;
background-color: rgba(var(--text-color), 0.04); background-color: rgba(var(--text-color), 0.04);
} }
#dashboard_view_selector strip-option {
--border-radius: 2rem;
}
.logo { .logo {
display: flex; display: flex;
@ -1299,7 +1287,6 @@ ul {
.container-header h4 { .container-header h4 {
flex: 1; flex: 1;
font-weight: 500;
} }
#intern_info_popup .grid > * { #intern_info_popup .grid > * {
@ -1346,7 +1333,6 @@ ul {
-moz-user-select: none; -moz-user-select: none;
user-select: none; user-select: none;
font-size: 0.85rem; font-size: 0.85rem;
font-weight: 500;
} }
.branch-button--active { .branch-button--active {
opacity: 1; opacity: 1;
@ -1368,7 +1354,6 @@ ul {
background: rgba(var(--foreground-color), 1); background: rgba(var(--foreground-color), 1);
} }
.task-list-item h4 { .task-list-item h4 {
font-weight: 500;
margin: 0; margin: 0;
} }
.task-list-item .task-title { .task-list-item .task-title {
@ -1827,7 +1812,6 @@ input[type=date]:focus {
fill: var(--accent-color); fill: var(--accent-color);
} }
.pinned-card .project__title { .pinned-card .project__title {
font-weight: 500;
color: rgba(var(--text-color), 0.9); color: rgba(var(--text-color), 0.9);
} }
.pinned-card .project__title:hover { .pinned-card .project__title:hover {

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -73,9 +73,19 @@ body[data-theme="dark"] {
filter: invert(1); filter: invert(1);
} }
} }
.calistoga { .overpass {
font-weight: 400; font-weight: 700;
font-family: "Calistoga", cursive; font-family: "Overpass", sans-serif;
}
h1,
h2,
h3,
h4,
h5,
h6 {
letter-spacing: -0.01em;
font-weight: 700;
font-family: "Overpass", sans-serif;
} }
p, p,
strong { strong {
@ -278,10 +288,6 @@ cube-loader {
--size: 1.2rem; --size: 1.2rem;
} }
sm-form {
--gap: 1rem;
}
sm-select { sm-select {
--padding: 0.8rem; --padding: 0.8rem;
--min-width: fit-content; --min-width: fit-content;
@ -295,30 +301,16 @@ sm-option {
font-size: 0.9rem; font-size: 0.9rem;
} }
strip-select { sm-chips {
--gap: 0.3rem; --gap: 0.3rem;
} }
strip-option { sm-chip {
position: relative; position: relative;
font-size: 0.9rem; font-size: 0.9rem;
--border-radius: 0.3rem; --border-radius: 0.3rem;
user-select: none; user-select: none;
} &[selected] {
sm-button {
--border-radius: 0.3rem;
&[variant="primary"] {
.icon {
fill: rgba(var(--background-color), 1);
}
}
&[disabled] {
.icon {
fill: rgba(var(--text-color), 0.6);
}
} }
} }
@ -687,7 +679,6 @@ ul {
flex-direction: column; flex-direction: column;
h4 { h4 {
font-weight: 500;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
@ -1122,10 +1113,6 @@ ul {
background-color: #00c853 !important; background-color: #00c853 !important;
} }
.task-title {
font-weight: 500;
}
.padding { .padding {
padding: 1rem; padding: 1rem;
} }
@ -1137,13 +1124,10 @@ ul {
align-content: flex-start; align-content: flex-start;
} }
#dashboard_view_selector { #dashboard_view_selector {
border-radius: 2rem; border-radius: 0.5rem;
margin: 0 auto; margin: 0 auto;
padding: 0.3rem; padding: 0.3rem;
background-color: rgba(var(--text-color), 0.04); background-color: rgba(var(--text-color), 0.04);
strip-option {
--border-radius: 2rem;
}
} }
.logo { .logo {
display: flex; display: flex;
@ -1294,7 +1278,6 @@ ul {
.container-header h4 { .container-header h4 {
flex: 1; flex: 1;
font-weight: 500;
} }
#intern_info_popup { #intern_info_popup {
@ -1339,7 +1322,6 @@ ul {
align-items: center; align-items: center;
user-select: none; user-select: none;
font-size: 0.85rem; font-size: 0.85rem;
font-weight: 500;
&--active { &--active {
opacity: 1; opacity: 1;
color: white; color: white;
@ -1359,7 +1341,6 @@ ul {
border-radius: 0.5rem; border-radius: 0.5rem;
background: rgba(var(--foreground-color), 1); background: rgba(var(--foreground-color), 1);
h4 { h4 {
font-weight: 500;
margin: 0; margin: 0;
} }
.task-title { .task-title {
@ -1801,7 +1782,6 @@ input[type="date"] {
} }
} }
.project__title { .project__title {
font-weight: 500;
color: rgba(var(--text-color), 0.9); color: rgba(var(--text-color), 0.9);
&:hover { &:hover {
color: var(--accent-color); color: var(--accent-color);

View File

@ -11,7 +11,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link <link
href="https://fonts.googleapis.com/css2?family=Calistoga&family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap" href="https://fonts.googleapis.com/css2?family=Overpass:ital,wght@0,700;0,900;1,700;1,900&family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap"
rel="stylesheet"> rel="stylesheet">
<script src="components.js" defer></script> <script src="components.js" defer></script>
<script id="floGlobals"> <script id="floGlobals">
@ -93,7 +93,7 @@
<div id="landing" class="grid inner-page hidden"> <div id="landing" class="grid inner-page hidden">
<div class="gap-1-5 landing__card"> <div class="gap-1-5 landing__card">
<div class="grid gap-1-5"> <div class="grid gap-1-5">
<h1 class="calistoga" style="max-width: 26rem;"> <h1 class="overpass" style="max-width: 26rem;">
Blockchain based <br> Internship Platform Blockchain based <br> Internship Platform
</h1> </h1>
<div class="flex gap-0-3"> <div class="flex gap-0-3">
@ -306,12 +306,12 @@
<section id="dashboard_page" class="inner-page hidden"></section> <section id="dashboard_page" class="inner-page hidden"></section>
<section id="admin_page" class="inner-page hidden"> <section id="admin_page" class="inner-page hidden">
<div id="admin_page__header" class="flex align-center space-between"> <div id="admin_page__header" class="flex align-center space-between">
<strip-select id="admin_view_selector"> <sm-chips id="admin_view_selector">
<strip-option value="0" selected>Projects</strip-option> <sm-chip value="projects" selected>Projects</sm-chip>
<strip-option value="1">Interns</strip-option> <sm-chip value="interns">Interns</sm-chip>
<strip-option value="2">Task display</strip-option> <sm-chip value="task_display">Task display</sm-chip>
<strip-option value="3">Requests</strip-option> <sm-chip value="requests">Requests</sm-chip>
</strip-select> </sm-chips>
<button class="button button--small button--primary admin-option" onclick="commitToChanges()"> <button class="button button--small button--primary admin-option" onclick="commitToChanges()">
<svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" <svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
width="24" height="24"> width="24" height="24">
@ -564,20 +564,7 @@
</svg> </svg>
</button> </button>
</header> </header>
<section class="grid gap-1"> <section id="intern_info__wrapper" class="grid gap-1"></section>
<div id="intern_info__initials" class="intern-card__initials"></div>
<h3 id="intern_info__name">Intern name</h3>
<sm-copy id="intern_info__flo_id"></sm-copy>
<div id="update_intern_score" class="flex align-center">
<svg class="icon icon--star margin-right-0-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
width="24" height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path
d="M12 18.26l-7.053 3.948 1.575-7.928L.587 8.792l8.027-.952L12 .5l3.386 7.34 8.027.952-5.935 5.488 1.575 7.928z" />
</svg>
<h4 id="intern_info__score"></h4>
</div>
</section>
</sm-popup> </sm-popup>
<sm-popup id="intern_list_popup"> <sm-popup id="intern_list_popup">
@ -742,6 +729,20 @@
</div> </div>
</sm-form> </sm-form>
</sm-popup> </sm-popup>
<sm-popup id="rate_participants_popup">
<header slot="header" class="popup__header">
<button class="popup__header__close justify-self-start" onclick="closePopup()">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" />
<path
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
</svg>
</button>
<h3>Rate participants</h3>
</header>
<div id="rating_wrapper" class="flex flex-direction-column gap-1-5"></div>
</sm-popup>
<sm-popup id="secure_pwd_popup"> <sm-popup id="secure_pwd_popup">
<header slot="header" class="popup__header"> <header slot="header" class="popup__header">
<button class="popup__header__close justify-self-start" onclick="closePopup()"> <button class="popup__header__close justify-self-start" onclick="closePopup()">
@ -1123,24 +1124,26 @@
renderedAssignedTasks = html`No task assigned yet.`; renderedAssignedTasks = html`No task assigned yet.`;
} }
} }
if (!subPageId1) {
subPageId1 = typeOfUser === 'intern' ? 'my_tasks' : 'all_tasks'
}
//creates cards for highest performing interns //creates cards for highest performing interns
//sort interns earned points //sort interns earned points
const highPerformingInterns = Object.keys(RIBC.getInternList()).sort((a, b) => RIBC.getInternRating(b) - RIBC.getInternRating(a)); const highPerformingInterns = Object.keys(RIBC.getInternList()).sort((a, b) => RIBC.getInternRating(b) - RIBC.getInternRating(a));
const routedToAllTasks = (subPageId1 && subPageId1 === 'all_tasks') || (!subPageId1 && typeOfUser !== 'intern');
renderElem(getRef('dashboard_page'), html` renderElem(getRef('dashboard_page'), html`
<strip-select id="dashboard_view_selector" class="margin-right-auto" onchange=${handleDashboardViewChange}> <sm-chips id="dashboard_view_selector" class="margin-right-auto" onchange=${handleDashboardViewChange}>
${typeOfUser === 'intern' ? html`<strip-option value="intern_view" selected>My tasks</strip-option>` : ''} ${typeOfUser === 'intern' ? html`<sm-chip value="intern_view" selected>My tasks</sm-chip>` : ''}
<strip-option value="dashboard_tasks_wrapper" ?selected=${routedToAllTasks}>All tasks</strip-option> <sm-chip value="dashboard_tasks_wrapper" ?selected=${subPageId1 === 'all_tasks'}>All tasks</sm-chip>
<strip-option value="projects_wrapper" ?selected=${subPageId1 === 'projects'}>Projects</strip-option> <sm-chip value="projects_wrapper" ?selected=${subPageId1 === 'projects'}>Projects</sm-chip>
${floGlobals.isMobileView ? html`<strip-option value="intern_leaderboard_container">Leaderboard</strip-option>` : ''} ${floGlobals.isMobileView ? html`<sm-chip value="intern_leaderboard_container">Leaderboard</sm-chip>` : ''}
</strip-select> </sm-chips>
${typeOfUser === 'intern' ? html` ${typeOfUser === 'intern' ? html`
<section id="intern_view" class="intern-option dashboard-view__item"> <section id="intern_view" class="intern-option dashboard-view__item">
<ul id="assigned_task_list">${renderedAssignedTasks}</ul> <ul id="assigned_task_list">${renderedAssignedTasks}</ul>
</section> </section>
` : ''} ` : ''}
<div id="dashboard_tasks_wrapper" class=${`flex flex-direction-column justify-center dashboard-view__item ${typeOfUser === 'intern' ? 'hidden' : ''}`}>${render.displayTasks(params?.category, params?.search)}</div> <div id="dashboard_tasks_wrapper" class=${`flex flex-direction-column justify-center dashboard-view__item ${typeOfUser === 'intern' ? 'hidden' : ''}`}>${render.displayTasks(params?.category, params?.search)}</div>
<div id="projects_wrapper" class="grid gap-2 align-items-start dashboard-view__item hidden"></div> <div id="projects_wrapper" class="grid gap-2 align-items-start dashboard-view__item hidden">${render.dashProjects()}</div>
<div id="intern_leaderboard_container" class="container-card dashboard-view__item hide-on-mobile"> <div id="intern_leaderboard_container" class="container-card dashboard-view__item hide-on-mobile">
<div class="container-header"> <div class="container-header">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <path fill="none" d="M0 0h24v24H0z" /> <path d="M12 7a8 8 0 1 1 0 16 8 8 0 0 1 0-16zm0 3.5l-1.323 2.68-2.957.43 2.14 2.085-.505 2.946L12 17.25l2.645 1.39-.505-2.945 2.14-2.086-2.957-.43L12 10.5zm1-8.501L18 2v3l-1.363 1.138A9.935 9.935 0 0 0 13 5.049L13 2zm-2 0v3.05a9.935 9.935 0 0 0-3.636 1.088L6 5V2l5-.001z" /> </svg> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <path fill="none" d="M0 0h24v24H0z" /> <path d="M12 7a8 8 0 1 1 0 16 8 8 0 0 1 0-16zm0 3.5l-1.323 2.68-2.957.43 2.14 2.085-.505 2.946L12 17.25l2.645 1.39-.505-2.945 2.14-2.086-2.957-.43L12 10.5zm1-8.501L18 2v3l-1.363 1.138A9.935 9.935 0 0 0 13 5.049L13 2zm-2 0v3.05a9.935 9.935 0 0 0-3.636 1.088L6 5V2l5-.001z" /> </svg>
@ -1153,11 +1156,10 @@
</div> </div>
</div> </div>
`) `)
renderElem(getRef('projects_wrapper'), render.dashProjects()) changeDashboardView(getKeyByValue(floGlobals.dashboardPages, subPageId1))
if (params?.taskId) { if (params?.taskId) {
showTaskDetails(params.taskId) showTaskDetails(params.taskId)
} } else
else
hideTaskDetails() hideTaskDetails()
break; break;
case 'updates_page': { case 'updates_page': {
@ -1225,9 +1227,10 @@
if (typeOfUser !== 'admin') return; if (typeOfUser !== 'admin') return;
//show projects //show projects
if (subPageId1) { if (subPageId1) {
getRef('admin_view_selector').value = subPageId1;
const viewIndex = ['projects', 'interns', 'task_display', 'requests'].findIndex(page => page === subPageId1); const viewIndex = ['projects', 'interns', 'task_display', 'requests'].findIndex(page => page === subPageId1);
getRef('admin_view_selector').value = viewIndex; showChildElement(getRef('admin_views'), viewIndex, { entry: viewIndex > currentViewIndex ? slideInLeft : slideInRight, exit: viewIndex > currentViewIndex ? slideOutLeft : slideOutRight });
showChildElement(getRef('admin_views'), viewIndex); currentViewIndex = viewIndex;
switch (subPageId1) { switch (subPageId1) {
case 'projects': case 'projects':
render.projectList(getRef('admin_page__project_list'), getSortedProjectList(), true) render.projectList(getRef('admin_page__project_list'), getSortedProjectList(), true)
@ -1243,6 +1246,7 @@
getRef('projects_container__left').classList.remove('hide-on-mobile') getRef('projects_container__left').classList.remove('hide-on-mobile')
getRef('project_editing_panel').classList.add('hidden') getRef('project_editing_panel').classList.add('hidden')
history.replaceState(null, '', '#/admin_page/projects') history.replaceState(null, '', '#/admin_page/projects')
getRef('admin_page__project_list').querySelectorAll('.project-card').forEach(project => project.classList.remove('project-card--active'))
} }
break; break;
case 'interns': case 'interns':
@ -1315,7 +1319,6 @@
dragger = dragula([getRef('display_task_map'), getRef('all_tasks')]) dragger = dragula([getRef('display_task_map'), getRef('all_tasks')])
dragger.on('dragend', function (el, source) { dragger.on('dragend', function (el, source) {
const newOrder = Array.from(getRef('display_task_map').children).map(el => el.dataset.taskId) const newOrder = Array.from(getRef('display_task_map').children).map(el => el.dataset.taskId)
console.log(newOrder)
RIBC.admin.setDisplayedTasks(newOrder) RIBC.admin.setDisplayedTasks(newOrder)
}); });
break; break;
@ -1363,14 +1366,14 @@
getRef('private_key_field').focusIn() getRef('private_key_field').focusIn()
break; break;
} }
if (pageId !== 'dashboard_page') { if (appState.lastPage === 'dashboard_page') {
renderElem(getRef('dashboard_page'), html``) renderElem(getRef('dashboard_page'), html``)
} }
if (pageId !== 'settings_page') { if (appState.lastPage === 'settings_page') {
renderElem(getRef('settings_page'), html``) renderElem(getRef('settings_page'), html``)
} }
appState.lastPage = pageId
} }
appState.lastPage = pageId
} }
} }
// class based lazy loading // class based lazy loading
@ -1627,8 +1630,9 @@
parent.style.overflow = '' parent.style.overflow = ''
} }
parent.children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden') parent.children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
if (entry) if (entry) {
parent.children[index].animate(entry, animOptions).onfinish = () => resolve() parent.children[index].animate(entry, animOptions).onfinish = () => resolve()
}
} else { } else {
visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hidden') visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hidden')
parent.children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden') parent.children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
@ -1739,9 +1743,9 @@
// render categories // render categories
let renderedCategories = [] let renderedCategories = []
if (availableCategories.size > 1) { if (availableCategories.size > 1) {
renderedCategories = [html`<strip-option value='all' ?selected=${category === 'all'}>All</strip-option>`]; renderedCategories = [html`<sm-chip value='all' ?selected=${category === 'all'}>All</sm-chip>`];
availableCategories.forEach(categoryID => { availableCategories.forEach(categoryID => {
renderedCategories.push(html`<strip-option value=${categoryID} ?selected=${categoryID === category}>${floGlobals.taskCategories[categoryID]}</strip-option>`) renderedCategories.push(html`<sm-chip value=${categoryID} ?selected=${categoryID === category}>${floGlobals.taskCategories[categoryID]}</sm-chip>`)
}) })
} }
setTimeout(() => { setTimeout(() => {
@ -1760,7 +1764,7 @@
</sm-input> </sm-input>
`: ''} `: ''}
</div> </div>
${availableCategories.size > 1 ? html`<strip-select id="task_category_selector" onchange='filterTasks()'>${renderedCategories}</strip-select>` : ''} ${availableCategories.size > 1 ? html`<sm-chips id="task_category_selector" onchange='filterTasks()'>${renderedCategories}</sm-chips>` : ''}
</div> </div>
<div class="grid gap-1"> <div class="grid gap-1">
<ul id="display_task_list" class="flex flex-direction-column gap-0-5 observe-empty-state">${renderedTasks}</ul> <ul id="display_task_list" class="flex flex-direction-column gap-0-5 observe-empty-state">${renderedTasks}</ul>
@ -2377,23 +2381,29 @@
} }
let pinnedProjects = []; let pinnedProjects = [];
let currentIntern;
let typeOfUser = 'general'; let typeOfUser = 'general';
floGlobals.dashboardPages = {
'intern_view': 'my_tasks',
'dashboard_tasks_wrapper': 'all_tasks',
'projects_wrapper': 'projects',
'intern_leaderboard_container': 'leaderboard',
}
// find key of the object by value
function getKeyByValue(object, value) {
return Object.keys(object).find(key => object[key] === value);
}
function handleDashboardViewChange(e) { function handleDashboardViewChange(e) {
changeDashboardView(e.target.value)
location.hash = `#/${appState.currentPage}/${floGlobals.dashboardPages[e.target.value]}`
}
function changeDashboardView(viewId = 'dashboard_tasks_wrapper') {
document.querySelectorAll('.dashboard-view__item').forEach(item => { document.querySelectorAll('.dashboard-view__item').forEach(item => {
if (item.id === 'intern_leaderboard_container') if (item.id === 'intern_leaderboard_container')
item.classList.add('hide-on-mobile') item.classList.add('hide-on-mobile')
else else
item.classList.add('hidden') item.classList.add('hidden')
}) })
document.querySelector(`#${e.target.value}`).classList.remove('hide-on-mobile', 'hidden') document.querySelector(`#${viewId}`).classList.remove('hide-on-mobile', 'hidden')
const dashboardPages = {
'intern_view': 'my_tasks',
'dashboard_tasks_wrapper': 'all_tasks',
'projects_wrapper': 'projects'
}
location.hash = `#/${appState.currentPage}/${dashboardPages[e.target.value]}`
} }
@ -2455,12 +2465,30 @@
function showInternInfo(e) { function showInternInfo(e) {
const internFloId = e.target.closest('.intern-card').dataset.internFloId; const internFloId = e.target.closest('.intern-card').dataset.internFloId;
const internName = RIBC.getInternList()[internFloId] const internName = RIBC.getInternList()[internFloId]
getRef('intern_info__initials').textContent = internName.split(' ').map(v => v.charAt(0)).join(''); const { completedTasks = [], active = true } = RIBC.getInternRecord(internFloId) || {}
getRef('intern_info__initials').style.setProperty('--color', `var(${getInternColor(internFloId)})`) renderElem(getRef('intern_info__wrapper'), html`
getRef('intern_info__name').textContent = internName; <div id="intern_info__initials" class="intern-card__initials" style=${`--color: var(${getInternColor(internFloId)})`}>${internName.split(' ').map(v => v.charAt(0)).join('')}</div>
getRef('intern_info__flo_id').value = currentIntern = internFloId; <h3 id="intern_info__name">${internName}</h3>
getRef('intern_info__score').textContent = RIBC.getInternRating(internFloId); // points earned by intern <sm-copy id="intern_info__flo_id" value=${internFloId}></sm-copy>
<div id="update_intern_score" class="flex align-center">
<svg class="icon icon--star margin-right-0-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> <path fill="none" d="M0 0h24v24H0z" /> <path d="M12 18.26l-7.053 3.948 1.575-7.928L.587 8.792l8.027-.952L12 .5l3.386 7.34 8.027.952-5.935 5.488 1.575 7.928z" /> </svg>
<h4 id="intern_info__score">0</h4>
</div>
`)
openPopup('intern_info_popup'); openPopup('intern_info_popup');
// animate number counting up within 1s from 0 to the intern's score
const scoreElem = getRef('intern_info__score')
const finalScore = RIBC.getInternRating(internFloId)
let score = 0;
const scoreInterval = setInterval(incrementNumber, 600 / finalScore)
function incrementNumber() {
scoreElem.textContent = score;
score++;
if (score > finalScore) {
clearInterval(scoreInterval)
}
}
incrementNumber()
} }
// opens a popup containing various project information // opens a popup containing various project information
@ -2535,12 +2563,8 @@
let currentViewIndex = 0; let currentViewIndex = 0;
getRef('admin_view_selector').addEventListener('change', (e) => { getRef('admin_view_selector').addEventListener('change', (e) => {
const newViewIndex = parseInt(e.target.value); location.hash = `#/${appState.currentPage}/${e.target.value}`
showChildElement(getRef('admin_views'), newViewIndex, { entry: newViewIndex > currentViewIndex ? slideInLeft : slideInRight, exit: newViewIndex > currentViewIndex ? slideOutLeft : slideOutRight }); getRef('admin_page_nav_button').href = `#/${appState.currentPage}/${e.target.value}`
currentViewIndex = parseInt(e.target.value);
const viewIds = ['projects', 'interns', 'task_display', 'requests']
location.hash = `#/${appState.currentPage}/${viewIds[e.target.value]}`
getRef('admin_page_nav_button').href = `#/${appState.currentPage}/${viewIds[e.target.value]}`
}) })
function toggleEditing(target) { function toggleEditing(target) {
@ -2555,17 +2579,63 @@
return '₹0'; return '₹0';
return amount.toLocaleString(currency === 'inr' ? `en-IN` : 'en-US', { style: 'currency', currency, maximumFractionDigits: 0 }) return amount.toLocaleString(currency === 'inr' ? `en-IN` : 'en-US', { style: 'currency', currency, maximumFractionDigits: 0 })
} }
delegate(getRef('task_list'), 'change', 'sm-checkbox', (e) => { delegate(getRef('task_list'), 'mousedown', 'sm-checkbox', (e) => {
e.preventDefault();
currentTask = e.target.closest('.task-list-item'); currentTask = e.target.closest('.task-list-item');
const taskStatus = e.target.checked ? 'completed' : 'incomplete' if (e.delegateTarget.checked) {
RIBC.admin.putTaskStatus(taskStatus, appState.params.id, appState.params.branch, currentTask.dataset.taskId) getConfirmation('Mark this task as incomplete?', { confirmText: 'Mark as incomplete' }).then(res => {
if (e.target.checked) { if (res) {
// remove task from displayed list RIBC.admin.putTaskStatus('incomplete', appState.params.id, appState.params.branch, currentTask.dataset.taskId)
const taskId = `${appState.params.id}_${appState.params.branch}_${currentTask.dataset.taskId}`; currentTask.querySelector('sm-checkbox').checked = false;
const filteredTasks = RIBC.getDisplayedTasks().filter(task => task !== taskId) // TODO: remove task scores from intern rating
RIBC.admin.setDisplayedTasks(filteredTasks) }
})
} else {
const assignedInterns = RIBC.getAssignedInterns(appState.params.id, appState.params.branch, currentTask.dataset.taskId);
renderElem(getRef('rating_wrapper'), html`
<h4>${currentTask.querySelector('.task-title').textContent}</h4>
<sm-form>
${assignedInterns.map((intern, index) => html`
<div class="flex flex-direction-column gap-0-5 rating-part" data-intern-id=${intern}>
<h4>${RIBC.getInternList()[intern]}</h4>
<div class="flex gap-0-5">
<sm-input type="number" min="0" max="50" class="flex-1" placeholder="Rate out of 50" error-text="Points must be between 0-50" required></sm-input>
<input class="flex-1" type="date" value=${formatDate(new Date())} placeholder="Completion date" aria-label="Set date of completion" required>
</div>
</div>
`)}
<button id="rate_participants_btn" class="button button--primary" type="submit" disabled onclick="rateParticipants()"> Rate </button>
</sm-form>
`)
openPopup('rate_participants_popup')
} }
}) })
// format unix timestamp to yyyy-mm-dd
function formatDate(unixTimestamp) {
const date = new Date(unixTimestamp);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
return `${year}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`;
}
function markTaskAsCompleted() {
RIBC.admin.putTaskStatus('completed', appState.params.id, appState.params.branch, currentTask.dataset.taskId)
// remove task from displayed list
const taskId = `${appState.params.id}_${appState.params.branch}_${currentTask.dataset.taskId}`;
const filteredTasks = RIBC.getDisplayedTasks().filter(task => task !== taskId)
}
function rateParticipants() {
document.querySelectorAll('.rating-part').forEach((ratingPart) => {
const taskId = `${appState.params.id}_${appState.params.branch}_${currentTask.dataset.taskId}`;
const internId = ratingPart.dataset.internId;
const score = 50 + parseInt(ratingPart.querySelector('sm-input').value.trim());
const completionDate = ratingPart.querySelector('input').value;
RIBC.admin.addTaskScore(internId, taskId, score, { completionDate })
})
markTaskAsCompleted()
closePopup()
currentTask.querySelector('sm-checkbox').checked = true;
}
delegate(getRef('task_list'), 'change', 'sm-select', (e) => { delegate(getRef('task_list'), 'change', 'sm-select', (e) => {
currentTask = e.target.closest('.task-list-item'); currentTask = e.target.closest('.task-list-item');
if (!currentTask) return; if (!currentTask) return;
@ -2580,16 +2650,14 @@
if (!currentTask) return; if (!currentTask) return;
const ogTaskDetails = RIBC.getTaskDetails(appState.params.id, appState.params.branch, currentTask.dataset.taskId) const ogTaskDetails = RIBC.getTaskDetails(appState.params.id, appState.params.branch, currentTask.dataset.taskId)
const newTaskDetails = {} const newTaskDetails = {}
let valid = false;
if (e.target.isContentEditable) { if (e.target.isContentEditable) {
e.target.contentEditable = false e.target.contentEditable = false
newTaskDetails[e.target.dataset.editField] = DOMPurify.sanitize(e.target.innerHTML.trim()) newTaskDetails[e.target.dataset.editField] = DOMPurify.sanitize(e.target.innerHTML.trim())
valid = true;
} else if (e.target.closest('sm-input')) { } else if (e.target.closest('sm-input')) {
newTaskDetails[e.target.dataset.editField] = parseInt(e.target.value) newTaskDetails[e.target.dataset.editField] = parseInt(e.target.value)
valid = true; } else {
return;
} }
if (!valid) return;
if (ogTaskDetails[e.target.dataset.editField] !== newTaskDetails[e.target.dataset.editField]) { if (ogTaskDetails[e.target.dataset.editField] !== newTaskDetails[e.target.dataset.editField]) {
RIBC.admin.editTaskDetails(newTaskDetails, appState.params.id, appState.params.branch, currentTask.dataset.taskId) RIBC.admin.editTaskDetails(newTaskDetails, appState.params.id, appState.params.branch, currentTask.dataset.taskId)
notify('Changes saved locally, commit the changes to make them permanent', 'success') notify('Changes saved locally, commit the changes to make them permanent', 'success')
@ -3003,6 +3071,9 @@
floGlobals.selectedInterns.clear() floGlobals.selectedInterns.clear()
getRef('assign_interns_button').disabled = true getRef('assign_interns_button').disabled = true
break; break;
case 'rate_participants_popup':
renderElem(getRef('rating_wrapper'), html``)
break;
} }
if (popupStack.items.length === 0) { if (popupStack.items.length === 0) {
getRef('main_page').removeAttribute('inert') getRef('main_page').removeAttribute('inert')

View File

@ -15,7 +15,7 @@
floCloudAPI.requestObjectData("RIBC").then(result => { floCloudAPI.requestObjectData("RIBC").then(result => {
if (!floGlobals.appObjects.RIBC) if (!floGlobals.appObjects.RIBC)
floGlobals.appObjects.RIBC = {}; floGlobals.appObjects.RIBC = {};
var objectList = ["projectMap", "projectBranches", "projectTaskDetails", "projectDetails", "internList", "internRating", "internsAssigned", "projectTaskStatus", "displayedTasks"] var objectList = ["projectMap", "projectBranches", "projectTaskDetails", "projectDetails", "internList", "internRating", "internRecord", "internsAssigned", "projectTaskStatus", "displayedTasks"]
objectList.forEach(obj => { objectList.forEach(obj => {
if (!floGlobals.appObjects.RIBC[obj]) if (!floGlobals.appObjects.RIBC[obj])
floGlobals.appObjects.RIBC[obj] = {}; floGlobals.appObjects.RIBC[obj] = {};
@ -103,6 +103,7 @@
Ribc.getTaskStatus = (project, branch, task) => _.projectTaskStatus[project + "_" + branch + "_" + task]; Ribc.getTaskStatus = (project, branch, task) => _.projectTaskStatus[project + "_" + branch + "_" + task];
Ribc.getInternList = () => _.internList; Ribc.getInternList = () => _.internList;
Ribc.getInternRating = (floID) => _.internRating[floID]; Ribc.getInternRating = (floID) => _.internRating[floID];
Ribc.getInternRecord = (floID) => _.internRecord[floID];
Ribc.getAssignedInterns = (projectCode, branch, taskNumber) => _.internsAssigned[projectCode + "_" + branch + "_" + taskNumber] Ribc.getAssignedInterns = (projectCode, branch, taskNumber) => _.internsAssigned[projectCode + "_" + branch + "_" + taskNumber]
Ribc.getAllTasks = () => _.projectTaskDetails Ribc.getAllTasks = () => _.projectTaskDetails
Ribc.getDisplayedTasks = () => floGlobals.appObjects.RIBC.displayedTasks || []; Ribc.getDisplayedTasks = () => floGlobals.appObjects.RIBC.displayedTasks || [];
@ -164,7 +165,11 @@
if (floID in _.internList) if (floID in _.internList)
return false return false
_.internList[floID] = internName _.internList[floID] = internName
_.internRating[floID] = 1 _.internRating[floID] = 0
_.internRecord[floID] = {
active: true,
completedTasks: {},
}
return true; return true;
} }
Admin.renameIntern = function (floID, newName) { Admin.renameIntern = function (floID, newName) {
@ -179,20 +184,38 @@
return false return false
delete _.internList[floID] delete _.internList[floID]
delete _.internRating[floID] delete _.internRating[floID]
delete _.internRecord[floID]
for (const taskId in _.projectTaskDetails) { for (const taskId in _.projectTaskDetails) {
if (_.internsAssigned[taskId].includes(floID)) if (_.internsAssigned[taskId].includes(floID))
_.internsAssigned[taskId] = _.internsAssigned[taskId].filter(id => id != floID) _.internsAssigned[taskId] = _.internsAssigned[taskId].filter(id => id != floID)
} }
return true; return true;
} }
Admin.addTaskScore = function (floID, taskId, score, details = {}) {
Admin.updateInternRating = function (floID, change = 0) {
if (!(floID in _.internList)) if (!(floID in _.internList))
return "Intern not found!" return false;
_.internRating[floID] += change if (!_.internRecord[floID])
return "Intern rating Updated"; _.internRecord[floID] = {
active: true,
completedTasks: {},
}
_.internRecord[floID].completedTasks[taskId] = {
score,
...details
};
let totalScore = 0;
for (const taskId in _.internRecord[floID].completedTasks) {
totalScore += _.internRecord[floID].completedTasks[taskId].score;
}
_.internRating[floID] = totalScore;
return true;
}
Admin.setInternStatus = function (floID, active = true) {
if (!(floID in _.internList))
return false;
_.internRecord[floID].active = active;
return true;
} }
Ribc.getTaskRequests = function (ignoreProcessed = true) { Ribc.getTaskRequests = function (ignoreProcessed = true) {
var taskRequests = Object.values(floGlobals.generalDataset("TaskRequests")).map(data => { var taskRequests = Object.values(floGlobals.generalDataset("TaskRequests")).map(data => {
return { return {

2
scripts/ribc.min.js vendored

File diff suppressed because one or more lines are too long