Merge branch 'release/1.4.0'
This commit is contained in:
commit
12761b3103
@ -1,14 +1,19 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends "base.html" %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
<script defer src="{% static "scripts/stimulus.umd.js" %}"></script>
|
||||||
|
<script type="module" defer src="{% static "scripts/index.js" %}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<article class="panel">
|
<article class="panel">
|
||||||
<header>
|
<header>
|
||||||
<h1>Hi, {{user.first_name}}</h1>
|
<h1>Today, {% now "D, M j" %}</h1>
|
||||||
</header>
|
</header>
|
||||||
<section>
|
<section>
|
||||||
<h2>Today, {% now "D, M j" %}</h2>
|
|
||||||
<div>
|
<div>
|
||||||
|
<h2>Events</h2>
|
||||||
{% for event in today %}
|
{% for event in today %}
|
||||||
<div class="today__event">
|
<div class="today__event">
|
||||||
<strong class="today__date">{{event.date|date:"D, M j"}}</strong>
|
<strong class="today__date">{{event.date|date:"D, M j"}}</strong>
|
||||||
@ -21,12 +26,10 @@
|
|||||||
<span><a href="{% url 'event-update' event.pk %}">Edit</a></span>
|
<span><a href="{% url 'event-update' event.pk %}">Edit</a></span>
|
||||||
</div>
|
</div>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p><em>Nothing for today.</em></p>
|
<p><em>No events for today.</em></p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
{% if upcoming_events %}
|
||||||
<p><a href="{% url 'event-create' %}" class="action-button">Add event</a></p>
|
|
||||||
<section>
|
|
||||||
<h3>Upcoming (next seven days)</h3>
|
<h3>Upcoming (next seven days)</h3>
|
||||||
<div>
|
<div>
|
||||||
{% for event in upcoming_events %}
|
{% for event in upcoming_events %}
|
||||||
@ -42,7 +45,127 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
<p><a href="{% url 'event-list' %}">See all events</a></p>
|
<p><a href="{% url 'event-list' %}">See all events</a></p>
|
||||||
|
</section>
|
||||||
|
<p><a href="{% url 'event-create' %}" class="action-button">Add event</a></p>
|
||||||
|
<hr>
|
||||||
|
<section>
|
||||||
|
<h2>To-do's</h2>
|
||||||
|
<div class="todos__overdue">
|
||||||
|
|
||||||
|
<h4 class="--danger">Overdue</h4>
|
||||||
|
<div>
|
||||||
|
{% regroup overdue_todos by employee as overdue_list %}
|
||||||
|
{% for employee in overdue_list %}
|
||||||
|
<p><a href="{% url 'employee-detail' employee.grouper.pk %}">{{employee.grouper}}</a></p>
|
||||||
|
{% for todo in employee.list %}
|
||||||
|
<li
|
||||||
|
class="todo__item"
|
||||||
|
data-controller="todo"
|
||||||
|
data-todo-url-value="{% url 'todo-update' todo.employee.pk todo.pk %}"
|
||||||
|
data-todo-delete-url-value="{% url 'todo-delete' todo.employee.pk todo.pk %}"
|
||||||
|
>
|
||||||
|
<div class="todo_display"
|
||||||
|
data-todo-target="display"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
data-action="click->todo#toggle"
|
||||||
|
class="todo__checkbox_button {% if todo.completed %}todo__checkbox_button--completed{% endif %}"></span>
|
||||||
|
<span class="todo__description_display">{{todo.description}}</span>
|
||||||
|
<span class="todo__due_date">{% if todo.due_date %}{{todo.due_date}}{% endif %}</span>
|
||||||
|
<div>
|
||||||
|
{% if not todo.employee.archived %}
|
||||||
|
<button class="hidden_action" data-action="todo#edit" name="edit">edit</button>
|
||||||
|
<button class="hidden_action" data-action="todo#destroy" name="destroy">delete</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form
|
||||||
|
class="todo_form --hidden"
|
||||||
|
data-todo-target="form"
|
||||||
|
data-action="todo#post"
|
||||||
|
data-action="change->todo#change"
|
||||||
|
action="{% url 'todo-update' todo.employee.pk todo.pk %}"
|
||||||
|
method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input
|
||||||
|
data-action="todo#post"
|
||||||
|
data-todo-target="checkbox"
|
||||||
|
class="todo__checkbox_input"
|
||||||
|
name="completed"
|
||||||
|
type="checkbox"
|
||||||
|
{% if todo.completed %}checked{% endif %}
|
||||||
|
{% if todo.employee.archived %}disabled{% endif %}
|
||||||
|
>
|
||||||
|
<input name="description" type="text" value="{{todo.description}}">
|
||||||
|
<input name="due_date" type="date" value="{% if todo.due_date %}{{todo.due_date|date:"Y-m-d"}}{% endif %}">
|
||||||
|
<div class="form__savecancel">
|
||||||
|
<input class="action-button" type="submit" value="Save changes">
|
||||||
|
<a data-action="todo#cancel" href="">cancel</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h4>Due today</h4>
|
||||||
|
{% regroup todos by employee as todo_list %}
|
||||||
|
{% for employee in todo_list %}
|
||||||
|
<p><a href="{% url 'employee-detail' employee.grouper.pk %}">{{employee.grouper}}</a></p>
|
||||||
|
{% for todo in employee.list %}
|
||||||
|
<li
|
||||||
|
class="todo__item"
|
||||||
|
data-controller="todo"
|
||||||
|
data-todo-url-value="{% url 'todo-update' todo.employee.pk todo.pk %}"
|
||||||
|
data-todo-delete-url-value="{% url 'todo-delete' todo.employee.pk todo.pk %}"
|
||||||
|
>
|
||||||
|
<div class="todo_display"
|
||||||
|
data-todo-target="display"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
data-action="click->todo#toggle"
|
||||||
|
class="todo__checkbox_button {% if todo.completed %}todo__checkbox_button--completed{% endif %}"></span>
|
||||||
|
<span class="todo__description_display">{{todo.description}}</span>
|
||||||
|
<span class="todo__due_date">{% if todo.due_date %}{{todo.due_date}}{% endif %}</span>
|
||||||
|
<div>
|
||||||
|
{% if not todo.employee.archived %}
|
||||||
|
<button class="hidden_action" data-action="todo#edit" name="edit">edit</button>
|
||||||
|
<button class="hidden_action" data-action="todo#destroy" name="destroy">delete</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form
|
||||||
|
class="todo_form --hidden"
|
||||||
|
data-todo-target="form"
|
||||||
|
data-action="todo#post"
|
||||||
|
data-action="change->todo#change"
|
||||||
|
action="{% url 'todo-update' todo.employee.pk todo.pk %}"
|
||||||
|
method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input
|
||||||
|
data-action="todo#post"
|
||||||
|
data-todo-target="checkbox"
|
||||||
|
class="todo__checkbox_input"
|
||||||
|
name="completed"
|
||||||
|
type="checkbox"
|
||||||
|
{% if todo.completed %}checked{% endif %}
|
||||||
|
{% if todo.employee.archived %}disabled{% endif %}
|
||||||
|
>
|
||||||
|
<input name="description" type="text" value="{{todo.description}}">
|
||||||
|
<input name="due_date" type="date" value="{% if todo.due_date %}{{todo.due_date|date:"Y-m-d"}}{% endif %}">
|
||||||
|
<div class="form__savecancel">
|
||||||
|
<input class="action-button" type="submit" value="Save changes">
|
||||||
|
<a data-action="todo#cancel" href="">cancel</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<h3>Recent Activity</h3>
|
<h3>Recent Activity</h3>
|
||||||
|
|||||||
@ -13,7 +13,7 @@ from django.contrib.auth.models import User
|
|||||||
from .models import Profile
|
from .models import Profile
|
||||||
from .forms import AccountUpdateForm, ProfileUpdateForm
|
from .forms import AccountUpdateForm, ProfileUpdateForm
|
||||||
|
|
||||||
from board.models import LogEntry, Event
|
from board.models import LogEntry, Event, Todo
|
||||||
|
|
||||||
|
|
||||||
class ProfileView(LoginRequiredMixin, TemplateView):
|
class ProfileView(LoginRequiredMixin, TemplateView):
|
||||||
@ -26,6 +26,14 @@ class ProfileView(LoginRequiredMixin, TemplateView):
|
|||||||
enddate = today + timedelta(days=7)
|
enddate = today + timedelta(days=7)
|
||||||
context['profile'] = self.request.user.profile
|
context['profile'] = self.request.user.profile
|
||||||
context['latest_activity'] = LogEntry.objects.all()[:10]
|
context['latest_activity'] = LogEntry.objects.all()[:10]
|
||||||
|
context['todos'] = Todo.objects.filter(
|
||||||
|
due_date=today,
|
||||||
|
completed=False
|
||||||
|
)
|
||||||
|
context['overdue_todos'] = Todo.objects.filter(
|
||||||
|
due_date__lt=today,
|
||||||
|
completed=False
|
||||||
|
)
|
||||||
context['today'] = Event.objects.filter(
|
context['today'] = Event.objects.filter(
|
||||||
date=today
|
date=today
|
||||||
)
|
)
|
||||||
|
|||||||
@ -71,23 +71,29 @@ class LogEntryForm(forms.ModelForm):
|
|||||||
class TodoForm(forms.ModelForm):
|
class TodoForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Todo
|
model = Todo
|
||||||
fields = ('completed', 'description')
|
fields = ('completed', 'description', 'due_date')
|
||||||
widgets = {
|
widgets = {
|
||||||
'completed': forms.CheckboxInput(attrs = {
|
'completed': forms.CheckboxInput(attrs = {
|
||||||
'class': 'todo__checkbox',
|
'class': 'todo__checkbox',
|
||||||
}),
|
}),
|
||||||
'description': forms.TextInput(attrs = {
|
'description': forms.TextInput(attrs = {
|
||||||
'autofocus': 'autofocus'
|
'autofocus': 'autofocus'
|
||||||
|
}),
|
||||||
|
'due_date': forms.DateInput(attrs = {
|
||||||
|
'type': 'date'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
class TodoCreateForm(forms.ModelForm):
|
class TodoCreateForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Todo
|
model = Todo
|
||||||
fields = ('description',)
|
fields = ('description', 'due_date')
|
||||||
widgets = {
|
widgets = {
|
||||||
'description': forms.TextInput(attrs = {
|
'description': forms.TextInput(attrs = {
|
||||||
'autofocus': 'autofocus'
|
'autofocus': 'autofocus'
|
||||||
|
}),
|
||||||
|
'due_date': forms.DateInput(attrs = {
|
||||||
|
'type': 'date'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
board/migrations/0002_todo_due_date.py
Normal file
18
board/migrations/0002_todo_due_date.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.2.5 on 2021-08-04 22:32
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('board', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='todo',
|
||||||
|
name='due_date',
|
||||||
|
field=models.DateField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -1,5 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse_lazy, reverse
|
from django.urls import reverse_lazy, reverse
|
||||||
|
from datetime import datetime
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|
||||||
@ -48,10 +49,18 @@ class LogEntry(models.Model):
|
|||||||
class Todo(models.Model):
|
class Todo(models.Model):
|
||||||
employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
|
employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
|
||||||
description = models.CharField(max_length=64)
|
description = models.CharField(max_length=64)
|
||||||
|
due_date = models.DateField(blank=True, null=True)
|
||||||
|
|
||||||
completed = models.BooleanField(default=False)
|
completed = models.BooleanField(default=False)
|
||||||
completed_at = models.DateTimeField(blank=True, null=True)
|
completed_at = models.DateTimeField(blank=True, null=True)
|
||||||
|
|
||||||
|
def is_due(self):
|
||||||
|
today = timezone.localtime(timezone.now()).date()
|
||||||
|
if self.due_date == today:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.employee}: {self.description}"
|
return f"{self.employee}: {self.description}"
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
|
<script defer src="{% static "scripts/stimulus.umd.js" %}"></script>
|
||||||
<script type="module" defer src="{% static "scripts/index.js" %}"></script>
|
<script type="module" defer src="{% static "scripts/index.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,46 @@
|
|||||||
<li class="todo__item">
|
<li
|
||||||
<form class="todo_form" action="{% url 'todo-update' employee.pk todo.pk %}" method="POST">
|
class="todo__item"
|
||||||
<label class="todo__details">
|
data-controller="todo"
|
||||||
<input class="todo__checkbox" name="completed" type="checkbox" {% if todo.completed %}checked{% endif %} {% if employee.archived %}disabled{% endif %}>
|
data-todo-url-value="{% url 'todo-update' employee.pk todo.pk %}"
|
||||||
<input name="description" type="hidden" value="{{todo.description}}">
|
data-todo-delete-url-value="{% url 'todo-delete' employee.pk todo.pk %}"
|
||||||
|
>
|
||||||
|
<div class="todo_display"
|
||||||
|
data-todo-target="display"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
data-action="click->todo#toggle"
|
||||||
|
class="todo__checkbox_button {% if todo.completed %}todo__checkbox_button--completed{% endif %}"></span>
|
||||||
<span class="todo__description_display">{{todo.description}}</span>
|
<span class="todo__description_display">{{todo.description}}</span>
|
||||||
</label>
|
<span class="todo__due_date">{% if todo.due_date %}{{todo.due_date}}{% endif %}</span>
|
||||||
|
<div class="todo__actions">
|
||||||
{% if not employee.archived %}
|
{% if not employee.archived %}
|
||||||
<a class="hidden_action" data-url="{% url 'todo-update' employee.pk todo.pk %}" href="#" name="edit">Edit…</a>
|
<button class="hidden_action" data-action="todo#edit" name="edit">edit</button>
|
||||||
<a class="hidden_action" data-url="{% url 'todo-delete' employee.pk todo.pk %}" href="#" name="destroy">Delete…</a>
|
<button class="hidden_action" data-action="todo#destroy" name="destroy">delete</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form
|
||||||
|
class="todo_form --hidden"
|
||||||
|
data-todo-target="form"
|
||||||
|
data-action="todo#post"
|
||||||
|
data-action="change->todo#change"
|
||||||
|
action="{% url 'todo-update' employee.pk todo.pk %}"
|
||||||
|
method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input
|
||||||
|
data-action="todo#post"
|
||||||
|
data-todo-target="checkbox"
|
||||||
|
class="todo__checkbox_input"
|
||||||
|
name="completed"
|
||||||
|
type="checkbox"
|
||||||
|
{% if todo.completed %}checked{% endif %}
|
||||||
|
{% if employee.archived %}disabled{% endif %}
|
||||||
|
>
|
||||||
|
<input name="description" type="text" value="{{todo.description}}">
|
||||||
|
<input name="due_date" type="date" value="{% if todo.due_date %}{{todo.due_date|date:"Y-m-d"}}{% endif %}">
|
||||||
|
<div>
|
||||||
|
<input class="action-button" type="submit" value="Save changes">
|
||||||
|
<a data-action="todo#cancel" href="">cancel</a>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
@ -1,4 +1,4 @@
|
|||||||
<ul id="todo__list">
|
<ul id="todo__list" data-controller="todo-list">
|
||||||
{% for todo in todo_list %}
|
{% for todo in todo_list %}
|
||||||
{% include "board/todo_detail.html" with todo=todo %}
|
{% include "board/todo_detail.html" with todo=todo %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import os
|
|||||||
from celery import Celery
|
from celery import Celery
|
||||||
|
|
||||||
# Set the default Django settings module for the 'celery' program.
|
# Set the default Django settings module for the 'celery' program.
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'onboard.settings_dev')
|
# os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'onboard.settings_dev')
|
||||||
|
|
||||||
app = Celery('onboard')
|
app = Celery('onboard')
|
||||||
|
|
||||||
|
|||||||
1
static/images/checkmark.svg
Normal file
1
static/images/checkmark.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg enable-background="new 0 0 50 52.5" viewBox="0 0 50 52.5" xmlns="http://www.w3.org/2000/svg"><path d="m14.4 50.4-13.3-17.7c-1.8-2.2-1.4-5.5 1-7.3 2.2-1.6 5.5-1.2 7.2 1l8.8 11.7 22.3-35.7c1.5-2.4 4.8-3.1 7.2-1.6s3.1 4.8 1.6 7.2l-26.1 42.1c-.9 1.4-2.5 2.4-4.2 2.4-.1 0-.1 0-.3 0-1.6 0-3.1-.7-4.2-2.1z" fill="#fff"/></svg>
|
||||||
|
After Width: | Height: | Size: 324 B |
140
static/scripts/controllers/todo_controller.js
Normal file
140
static/scripts/controllers/todo_controller.js
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import getCookie from "../get_cookie.js";
|
||||||
|
|
||||||
|
export default class extends Stimulus.Controller {
|
||||||
|
static values = { url: String, deleteUrl: String }
|
||||||
|
static get targets() {
|
||||||
|
return [ "completed", "form", "display", "checkbox" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.editing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// load() {
|
||||||
|
// fetch(`${this.urlValue}`)
|
||||||
|
// .then((response) => response.text())
|
||||||
|
// .then((html) => {
|
||||||
|
// this.formTarget.innerHTML = html;
|
||||||
|
// if (this.formTarget.querySelector("[name=destroy]")) {
|
||||||
|
// this.destroyButton = this.formTarget.querySelector("[name=destroy]")
|
||||||
|
// this.destroyButton.addEventListener("click", this.destroy.bind(this))
|
||||||
|
// }
|
||||||
|
// if (this.formTarget.querySelector("[name=edit]")) {
|
||||||
|
// this.editButton = this.formTarget.querySelector("[name=edit]")
|
||||||
|
// this.editButton.addEventListener("click", this.edit.bind(this))
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
validate() {
|
||||||
|
const inputs = new Set()
|
||||||
|
this.formTarget.querySelectorAll("input").forEach(input => {
|
||||||
|
inputs.add(input.checkValidity())
|
||||||
|
})
|
||||||
|
|
||||||
|
let valid = (inputs.has(false)) ? false : true
|
||||||
|
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
change(event) {
|
||||||
|
if (event.target.type === "checkbox") {
|
||||||
|
this.post(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
edit(event) {
|
||||||
|
this.formTarget.classList.remove("--hidden")
|
||||||
|
this.displayTarget.classList.add("--hidden")
|
||||||
|
this.editing = true
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(event) {
|
||||||
|
if (this.checkboxTarget.checked == true) {
|
||||||
|
this.checkboxTarget.checked = false
|
||||||
|
} else {
|
||||||
|
this.checkboxTarget.checked = true
|
||||||
|
}
|
||||||
|
if (this.validate()) {
|
||||||
|
this.post()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel(event) {
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
if (this.editing) {
|
||||||
|
this.formTarget.classList.add("--hidden")
|
||||||
|
this.displayTarget.classList.remove("--hidden")
|
||||||
|
this.editing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
post(event) {
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
// construct a new FormData object from the html form
|
||||||
|
const formData = new FormData(this.formTarget)
|
||||||
|
|
||||||
|
// get the csrftoken
|
||||||
|
const csrftoken = getCookie("csrftoken")
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: "POST",
|
||||||
|
body: new URLSearchParams(formData),
|
||||||
|
mode: "same-origin",
|
||||||
|
};
|
||||||
|
|
||||||
|
// construct a new Request passing in the csrftoken
|
||||||
|
const request = new Request(`${this.urlValue}`, {
|
||||||
|
headers: { "X-CSRFToken": csrftoken },
|
||||||
|
})
|
||||||
|
|
||||||
|
// finally make the post request and wait for the server to respond
|
||||||
|
fetch(request, options)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((html) => {
|
||||||
|
this.element.outerHTML = html
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
return error;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(event) {
|
||||||
|
const confirmation = confirm(
|
||||||
|
"Are you sure you would like to delete this entry?"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (confirmation) {
|
||||||
|
// get the csrftoken
|
||||||
|
const csrftoken = getCookie("csrftoken")
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: "POST",
|
||||||
|
mode: "same-origin",
|
||||||
|
};
|
||||||
|
|
||||||
|
// construct a new Request passing in the csrftoken
|
||||||
|
const request = new Request(`${this.deleteUrlValue}`, {
|
||||||
|
headers: { "X-CSRFToken": csrftoken },
|
||||||
|
})
|
||||||
|
|
||||||
|
// finally make the post request and wait for the server to respond
|
||||||
|
fetch(request, options)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((html) => {
|
||||||
|
this.element.innerHTML = html;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.remove()
|
||||||
|
}, 3000)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
return error;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,20 @@
|
|||||||
import Form from "./form.js";
|
// import Form from "./form.js";
|
||||||
import View from "./view.js";
|
// import View from "./view.js";
|
||||||
|
|
||||||
|
// import TodoListController from "./controllers/todo_list_controller.js"
|
||||||
|
import TodoController from "./controllers/todo_controller.js"
|
||||||
|
|
||||||
|
|
||||||
// constructor(element, forms, templateName, addButton, destination)
|
// constructor(element, forms, templateName, addButton, destination)
|
||||||
|
|
||||||
const todoListView = new View(
|
// const todoListView = new View(
|
||||||
document.querySelector("#todos"),
|
// document.querySelector("#todos"),
|
||||||
".todo_form",
|
// ".todo_form",
|
||||||
"#todo__list"
|
// "#todo__list"
|
||||||
)
|
// )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const application = Stimulus.Application.start()
|
||||||
|
// application.register("todo-list", TodoListController)
|
||||||
|
application.register("todo", TodoController)
|
||||||
|
|||||||
2294
static/scripts/stimulus.umd.js
Normal file
2294
static/scripts/stimulus.umd.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@
|
|||||||
--blue: #10638c;
|
--blue: #10638c;
|
||||||
--light-blue: #74c0e6;
|
--light-blue: #74c0e6;
|
||||||
--red: #8c1016;
|
--red: #8c1016;
|
||||||
|
--light-brown: #a69688;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@ -62,7 +63,7 @@ a {
|
|||||||
blockquote {
|
blockquote {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
padding-left: 2rem;
|
padding-left: 2rem;
|
||||||
border-left: 2px solid var(--blue);
|
border-left: 0.2rem solid var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
body > header {
|
body > header {
|
||||||
@ -154,8 +155,14 @@ article {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hidden_action {
|
.hidden_action {
|
||||||
|
visibility: hidden;
|
||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
display: none;
|
border: none;
|
||||||
|
background-color: var(--light-brown);
|
||||||
|
color: white;
|
||||||
|
padding: 0.15rem 0.5rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo__item {
|
.todo__item {
|
||||||
@ -164,19 +171,76 @@ article {
|
|||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
}
|
}
|
||||||
.todo__item:hover .hidden_action {
|
.todo__item:hover .hidden_action {
|
||||||
display: inline-block;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.todo_display {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 0.25fr 2fr 1fr 1fr;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0 1rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.todo__actions {
|
||||||
|
font-size: 0.889rem;
|
||||||
|
}
|
||||||
|
.todo__due_date {
|
||||||
|
color: var(--light-brown);
|
||||||
|
}
|
||||||
.todo__checkbox {
|
.todo__checkbox {
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
}
|
}
|
||||||
.todo_form {
|
.todo__checkbox_input {
|
||||||
display: flex;
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
z-index: -1;
|
||||||
}
|
}
|
||||||
.todo__details {
|
.todos__overdue {
|
||||||
display: flex;
|
background-color: var(--white);
|
||||||
align-items: center;
|
padding: 1rem;
|
||||||
flex-direction: row;
|
}
|
||||||
|
.todos__overdue h4 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.todo__checkbox_button {
|
||||||
|
display: inline-block;
|
||||||
|
width: 1.4em;
|
||||||
|
height: 1.4em;
|
||||||
|
border: 1px solid rgba(0,0,0,0.25);
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
vertical-align: top;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.todo__checkbox_button--completed {
|
||||||
|
position: relative;
|
||||||
|
border-color: rgba(0,0,0,0.1);
|
||||||
|
background-color: var(--blue);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.todo__checkbox_button--completed::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
background: url(../images/checkmark.svg) no-repeat center center;
|
||||||
|
background-size: auto;
|
||||||
|
background-size: 65%;
|
||||||
|
}
|
||||||
|
.todo_form {
|
||||||
|
display: grid;
|
||||||
|
row-gap: 1rem;
|
||||||
|
margin: 1rem 0;
|
||||||
|
width: 100%;
|
||||||
|
border: 0.0625rem solid rgba(0, 0, 0, 0.25);
|
||||||
|
background-color: var(--white);
|
||||||
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -207,10 +271,13 @@ article {
|
|||||||
.action-button--danger {
|
.action-button--danger {
|
||||||
background-color: var(--red);
|
background-color: var(--red);
|
||||||
}
|
}
|
||||||
|
.--danger {
|
||||||
|
color: var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* FORMS */
|
/* FORMS */
|
||||||
input[type=text]:not([name=description]),
|
input[type=text],
|
||||||
input[type=number],
|
input[type=number],
|
||||||
input[type=date],
|
input[type=date],
|
||||||
input[type=time],
|
input[type=time],
|
||||||
@ -226,14 +293,6 @@ textarea, select {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[name=description] {
|
|
||||||
border: 0.2rem solid var(--grey);
|
|
||||||
padding: 0.3rem;
|
|
||||||
font-family: inherit;
|
|
||||||
outline: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=radio], input[type=checkbox] {
|
input[type=radio], input[type=checkbox] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
@ -267,6 +326,15 @@ input:focus, textarea:focus, select:focus {
|
|||||||
border-color: var(--blue) !important;
|
border-color: var(--blue) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-left: 1rem;
|
||||||
|
border: none;
|
||||||
|
background-color: var(--light-brown);
|
||||||
|
color: white;
|
||||||
|
padding: 0.15rem 0.5rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -30,11 +30,7 @@
|
|||||||
<a href="{% url 'employee-list' %}">Employees</a>
|
<a href="{% url 'employee-list' %}">Employees</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav__auth">
|
<div class="nav__auth">
|
||||||
{% if user.first_name or user.last_name %}
|
|
||||||
<a href="{% url 'account-detail' user.pk %}">{{ user.first_name }} {{ user.last_name }}</a>
|
|
||||||
{% else %}
|
|
||||||
<a href="{% url 'account-detail' user.pk %}">Profile</a>
|
<a href="{% url 'account-detail' user.pk %}">Profile</a>
|
||||||
{% endif %}
|
|
||||||
<a class="action-button" href="{% url 'logout' %}">Logout</a>
|
<a class="action-button" href="{% url 'logout' %}">Logout</a>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user