Skip to content

Commit

Permalink
Running total of score on review form (#4169)
Browse files Browse the repository at this point in the history
Live score label added to edit review form

Fixes #3963

Co-authored-by: Ghulam Murtaza <[email protected]>
Co-authored-by: Saurabh Kumar <[email protected]>
  • Loading branch information
3 people authored Oct 31, 2024
1 parent 60484d9 commit 9153972
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 17 deletions.
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default [
...globals.browser,
...globals.commonjs,
jQuery: true,
Alpine: true,
},
},

Expand Down
1 change: 1 addition & 0 deletions hypha/apply/review/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class ScoreFieldWithoutTextBlock(OptionalFormFieldBlock):

name = "score without text"
field_class = forms.ChoiceField
widget = forms.Select(attrs={"data-score-field": "true"})

class Meta:
icon = "order"
Expand Down
2 changes: 1 addition & 1 deletion hypha/apply/review/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ScoredAnswerWidget(forms.MultiWidget):
def __init__(self, attrs=None):
_widgets = (
TinyMCE(attrs=attrs, mce_attrs=MCE_ATTRIBUTES_SHORT),
widgets.Select(attrs=attrs, choices=RATE_CHOICES),
widgets.Select(attrs={"data-score-field": "true"}, choices=RATE_CHOICES),
)
super().__init__(_widgets, attrs)

Expand Down
52 changes: 44 additions & 8 deletions hypha/apply/review/templates/review/review_edit_form.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{% extends "base-apply.html" %}
{% load i18n %}
{% load i18n static %}
{% block title %}{{ title }}{% endblock %}

{% block alpine_scripts %}
{{ block.super }}
<script defer src="{% static 'js/behaviours/review-score.js' %}"></script>
{% endblock %}

{% block content %}

{% adminbar %}
Expand All @@ -12,8 +18,19 @@

{% include "forms/includes/form_errors.html" with form=form %}

<div class="wrapper wrapper--medium wrapper--inner-space-medium">
<form class="form form--with-p-tags form--scoreable" action="" method="post" novalidate>
<div class="my-8 relative" x-data="reviewScore">
<!-- Review score sticky display -->
<div class="absolute h-full right-0 top-0 hidden lg:block">
<div
class="bg-arsenic text-white font-semibold inline-block px-3 py-1.5 mt-1 text-center sticky top-1"
x-clock
x-show="showScore"
>
{% trans "Score:" %} <span x-text="totalScore">-</span>
</div>
</div>

<form class="form form--scoreable max-w-3xl" action="" method="post" novalidate>
{{ form.media }}
{% csrf_token %}

Expand All @@ -22,7 +39,7 @@
{% endfor %}

{% for field in form.visible_fields %}
{# to be replaced with better logic when we use stream form #}
{# to be replaced with better logic when we use stream form #}
{% ifchanged field.field.group %}
{% for key, value in form.titles.items %}
{% if key == field.field.group %}
Expand All @@ -37,10 +54,29 @@ <h2>{{ value }}</h2>
{{ field }}
{% endif %}
{% endfor %}
{% if not object.id or object.is_draft %}
<button class="button button--submit button--top-space button--white" type="submit" name="{{ form.draft_button_name }}">{% trans "Save draft" %}</button>
{% endif %}
<button class="button button--submit button--top-space button--primary" type="submit" name="submit">{% trans "Submit" %}</button>
<div class="flex gap-4 items-center flex-wrap">

<button
class="button button--primary min-w-48"
type="submit"
name="submit"
>
{% trans "Submit" %}
</button>

{% if not object.id or object.is_draft %}
<button class="button button--white"
type="submit"
name="{{ form.draft_button_name }}"
>
{% trans "Save draft" %}
</button>
{% endif %}

<div class="text-fg-muted" x-clock x-show="showScore">
{% trans "Total Score:" %} <span x-text="totalScore"></span>
</div>
</div>
</form>
</div>
{% endblock %}
40 changes: 33 additions & 7 deletions hypha/apply/review/templates/review/review_form.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{% extends "base-apply.html" %}
{% load i18n %}
{% load i18n static %}
{% block title %}{{ title }}{% endblock %}

{% block alpine_scripts %}
{{ block.super }}
<script defer src="{% static 'js/behaviours/review-score.js' %}"></script>
{% endblock %}

{% block content %}

{% adminbar %}
Expand All @@ -23,9 +29,18 @@

{% include "forms/includes/form_errors.html" with form=form %}

<section class="my-8 flex justify-between">
<section class="my-8 flex justify-between relative" x-data="reviewScore">
<div class="absolute h-full right-0 top-0 hidden lg:block">
<div
class="bg-arsenic text-white font-semibold inline-block px-3 py-1.5 mt-1 text-center sticky top-1 float-end"
x-clock
x-show="showScore"
>
{% trans "Score:" %} <span x-text="totalScore">-</span>
</div>
</div>
{% if not has_submitted_review %}
<form class="form form--with-p-tags form--scoreable max-w-3xl flex-1" action="" method="post">
<form class="form form--scoreable max-w-3xl flex-1" action="" method="post">
{{ form.media }}
{% csrf_token %}

Expand All @@ -49,10 +64,21 @@ <h2>{{ value }}</h2>
{{ field.block }}
{% endif %}
{% endfor %}
{% if not object.id or object.is_draft %}
<button class="button button--submit button--top-space button--white" type="submit" name="{{ form.draft_button_name }}" formnovalidate>{% trans "Save draft" %}</button>
{% endif %}
<button class="button button--submit button--top-space button--primary" type="submit" name="submit">{% trans "Submit" %}</button>

<div class="flex gap-4 flex-wrap items-center">
{% if not object.id or object.is_draft %}
<button class="button button--white" type="submit" name="{{ form.draft_button_name }}" formnovalidate>
{% trans "Save draft" %}
</button>
{% endif %}
<button class="button button--primary min-w-48" type="submit" name="submit">
{% trans "Submit" %}
</button>
<div class="text-fg-muted" x-clock x-show="showScore">
{% trans "Total Score:" %} <span x-text="totalScore"></span>
</div>
</div>

</form>
<aside :class="showSubmission ? 'flex-1 ps-4' : ''">
<section
Expand Down
4 changes: 3 additions & 1 deletion hypha/apply/review/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ def test_func(self):
def get_context_data(self, **kwargs):
review = self.get_object()
return super().get_context_data(
submission=review.submission, title=_("Edit Review"), **kwargs
submission=review.submission,
title=_("Edit Review"),
**kwargs,
)

def get_defined_fields(self):
Expand Down
49 changes: 49 additions & 0 deletions hypha/static_src/javascript/behaviours/review-score.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Alpine.js data component for calculating review scores in the form.
* @returns {Object} The review score component object.
*/
document.addEventListener("alpine:init", () => {
Alpine.data("reviewScore", () => {
return {
/** @type {number} The calculated review score. */
totalScore: 0,

/**
* Initializes the component.
* Sets up event listeners for score calculation if applicable.
*/
init() {
this.selectors =
this.$el.querySelectorAll("[data-score-field]");
if (this.showScore) {
this.calculateScore();
this.selectors.forEach((selector) => {
selector.addEventListener(
"change",
this.calculateScore.bind(this)
);
});
}
},

/**
* Calculates the total score based on valid selector values.
*/
calculateScore() {
const validValues = [...this.selectors]
.map((selector) => parseInt(selector.value))
.filter((value) => !isNaN(value) && value !== 99);

this.totalScore = validValues.reduce((sum, value) => sum + value, 0);
},

/**
* Determines if the score should be shown.
* @returns {boolean} True if there are selectors, false otherwise.
*/
get showScore() {
return this.selectors.length > 0;
},
};
});
});
3 changes: 3 additions & 0 deletions hypha/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@

<!-- alpine js start -->
<style> [x-cloak] {display: none !important} </style>

<!-- Alpine Plugins: installed with npm -->
<script defer src="{% static 'js/vendor/alpine-focus.min.js' %}"></script>
{% block alpine_scripts %}{% endblock %}

<!-- Alpine Core: installed with npm -->
<script defer src="{% static 'js/vendor/alpine.min.js' %}"></script>
Expand All @@ -73,6 +75,7 @@
<!-- modules -->
<script type="module" src="{% static 'js/esm/github-relative-time-element-4-3-0.js' %}"></script>
<script type="module" src="{% static 'js/esm/github-filter-input-element-0-1-1.js' %}"></script>

{% include "includes/head_end.html" %}
</head>

Expand Down

0 comments on commit 9153972

Please sign in to comment.