From 26c8fa72bdc65ba9a0178132d604cc4933a5928c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Valenta?= <git@imaniti.org>
Date: Sat, 25 Feb 2023 00:51:54 +0100
Subject: [PATCH] add icons to tags, conditional signee admin field display

---
 contracts/admin.py                            | 10 +++-
 contracts/forms.py                            | 14 +++++
 contracts/models.py                           |  9 ++-
 .../templates/contracts/includes/tag.html     |  2 +-
 contracts/templates/contracts/index.html      | 24 ++++++--
 .../templates/contracts/view_contract.html    | 39 ++++++++++---
 static_src/admin/contract_file_form.js        | 12 ++++
 static_src/admin/signee_form.js               | 55 +++++++++++++++++--
 webpack.config.js                             |  4 ++
 9 files changed, 147 insertions(+), 22 deletions(-)
 create mode 100644 static_src/admin/contract_file_form.js

diff --git a/contracts/admin.py b/contracts/admin.py
index c8346d4..010bce2 100644
--- a/contracts/admin.py
+++ b/contracts/admin.py
@@ -2,7 +2,7 @@ from django.contrib import admin
 
 from shared.admin import MarkdownxGuardedModelAdmin
 
-from .forms import ContractAdminForm, SigneeAdminForm
+from .forms import ContractAdminForm, ContractFileAdminForm, SigneeAdminForm
 from .models import (
     Contract,
     Contractee,
@@ -27,6 +27,10 @@ class IndexHiddenModelAdmin(MarkdownxGuardedModelAdmin):
 # BEGIN Contracts
 
 
+class ContractFileAdmin(IndexHiddenModelAdmin):
+    form = ContractFileAdminForm
+
+
 class ContracteeSignatureInline(admin.TabularInline):
     model = ContracteeSignature
     extra = 0
@@ -39,6 +43,7 @@ class SigneeSignatureInline(admin.TabularInline):
 
 class ContractFileInline(admin.TabularInline):
     model = ContractFile
+    form = ContractFileAdminForm
     extra = 0
 
 
@@ -155,6 +160,7 @@ class SigneeAdmin(MarkdownxGuardedModelAdmin):
 
 
 class ContracteeRepresentativeInline(admin.TabularInline):
+    form = ContractFileAdminForm
     model = ContracteeRepresentative
     extra = 0
 
@@ -176,6 +182,8 @@ for model in (
 ):
     admin.site.register(model, IndexHiddenModelAdmin)
 
+admin.site.register(ContractFile, ContractFileAdmin)
+
 for model in (
     ContractIssue,
     ContractFilingArea,
diff --git a/contracts/forms.py b/contracts/forms.py
index 5ed21fb..4c1fc92 100644
--- a/contracts/forms.py
+++ b/contracts/forms.py
@@ -23,6 +23,20 @@ class ContractAdminForm(forms.ModelForm):
         }
 
 
+class ContractFileAdminForm(forms.ModelForm):
+    class Media:
+        js = (
+            "shared/admin_contract_file_form.js",
+        );
+
+    class Meta:
+        widgets = {
+            "name": forms.TextInput(attrs={
+                "list": "file-types"
+            }),
+        }
+
+
 class SigneeAdminForm(forms.ModelForm):
     class Media:
         js = (
diff --git a/contracts/models.py b/contracts/models.py
index 08970ef..4e4b33d 100644
--- a/contracts/models.py
+++ b/contracts/models.py
@@ -33,9 +33,10 @@ class Signee(models.Model):
     )
 
     class EntityTypes(models.TextChoices):
-        NATURAL_PERSON = "physical_person", "Fyzická osoba"
+        NATURAL_PERSON = "natural_person", "Fyzická osoba"
         LEGAL_ENTITY = "legal_entity", "Právnická osoba"
         BUSINESS_NATURAL_PERSON = "business_natural_person", "Podnikající fyzická osoba"
+        OTHER = "other", "Jiné"
 
     entity_type = models.CharField(
         max_length=23,
@@ -484,6 +485,12 @@ class Contract(models.Model):
 
         permissions = (("approve", "Schválit / zrušit schválení"),)
 
+    def get_public_files(self):
+        return ContractFile.objects.filter(
+            contract=self,
+            is_public=True,
+        ).all()
+
     def __str__(self) -> str:
         return self.name
 
diff --git a/contracts/templates/contracts/includes/tag.html b/contracts/templates/contracts/includes/tag.html
index 94012ee..dd1de6c 100644
--- a/contracts/templates/contracts/includes/tag.html
+++ b/contracts/templates/contracts/includes/tag.html
@@ -1,4 +1,4 @@
 <a
-    class="p-1.5 rounded-sm text-ellipsis bg-gray-200 duration-100 hover:bg-gray-300 hover:no-underline"
+    class="p-1.5 rounded-sm text-ellipsis whitespace-nowrap bg-gray-200 duration-100 hover:bg-gray-300 hover:no-underline"
     href="{{ url }}"
 >{% if icon %}<i class="{{ icon }} mr-2"></i>{% endif %}{{ content }}</a> 
diff --git a/contracts/templates/contracts/index.html b/contracts/templates/contracts/index.html
index 0606439..2e93906 100644
--- a/contracts/templates/contracts/index.html
+++ b/contracts/templates/contracts/index.html
@@ -14,9 +14,9 @@
                 <td class="font-bold">Název</td>
                 <td>Typy</td>
                 <td>Platná</td>
-                <td>Účinná od</td>
-                <td>Účinná do</td>
-                <td>Podepsána s</td>
+                <td class="whitespace-nowrap">Účinná od</td>
+                <td class="whitespace-nowrap">Účinná do</td>
+                <td class="whitespace-nowrap">Podepsána s</td>
             </tr>
         </thead>
         <tbody>
@@ -31,7 +31,9 @@
                     <td>
                         <ul class="flex flex-wrap gap-1.5">
                             {% for type in contract.types.all %}
-                                <li class="p-1.5 rounded-sm whitespace-nowrap bg-gray-200">{{ type.name }}</li>
+                                <li class="flex">
+                                     {% include "contracts/includes/tag.html" with url="#TODO" icon="ico--folder" content=type.name %}
+                                </li>
                             {% endfor %}
                         </ul>
                     </td>
@@ -39,12 +41,22 @@
                         <i class="{% if contract.legal_state == contract.LegalStates.VALID %}ico--checkmark{% else %}ico--cross{% endif %}"></i>
                     </td>
                     <td class="whitespace-nowrap">{{ contract.valid_start_date }}</td>
-                    <td class="whitespace-nowrap">{{ contract.valid_end_date }}</td>
+                    <td class="whitespace-nowrap">
+                        {% if contract.valid_end_date %}
+                            {{ contract.valid_end_date }}
+                        {% else %}
+                            <span class="text-grey-200">Neurčité</span>
+                        {% endif %}
+                    </td>
                     <td>
                         <ul class="flex flex-wrap gap-1.5">
                             {% for signature in contract.signee_signatures.all %}
                                 <li class="flex">
-                                     {% include "contracts/includes/tag.html" with url="#TODO" content=signature.signee.name %}
+                                    {% if signature.signee.entity_type == signature.signee.EntityTypes.LEGAL_ENTITY or signature.signee.entity_type == signature.signee.EntityTypes.OTHER %}
+                                        {% include "contracts/includes/tag.html" with url="#TODO" icon="ico--office" content=signature.signee.name %}
+                                    {% else %}
+                                        {% include "contracts/includes/tag.html" with url="#TODO" icon="ico--user" content=signature.signee.name %}
+                                    {% endif %}
                                 </li>
                             {% endfor %}
                         </ul>
diff --git a/contracts/templates/contracts/view_contract.html b/contracts/templates/contracts/view_contract.html
index eb475de..52996e9 100644
--- a/contracts/templates/contracts/view_contract.html
+++ b/contracts/templates/contracts/view_contract.html
@@ -2,7 +2,7 @@
 {% load subtract %}
 
 {% block content %}
-    <h1 class="head-alt-lg mb-10">{{ contract.name }}</h1>
+    <h1 class="head-alt-lg mb-10"><i class="ico--file-blank mr-4"></i>{{ contract.name }}</h1>
 
     <table class="table table-auto w-full table--striped table--bordered mb-7">
         <tbody>
@@ -24,7 +24,7 @@
                     <ul class="flex flex-wrap gap-1.5">
                         {% for type in contract.types.all %}
                             <li class="flex">
-                                 {% include "contracts/includes/tag.html" with url="#TODO" content=type.name %}
+                                 {% include "contracts/includes/tag.html" with url="#TODO" icon="ico--folder" content=type.name %}
                             </li>
                         {% endfor %}
                     </ul>
@@ -51,7 +51,7 @@
             <tr>
                 <td class="w-1/5 !p-2.5">Soubory</td>
                 <td class="w-4/5 !p-2.5">
-                    {% with contract.files.all as files %}
+                    {% with contract.get_public_files as files %}
                         {% if files|length != 0 %}
                             <ul class="flex gap-2">
                                 {% for file in files %}
@@ -83,7 +83,13 @@
             </tr>
             <tr>
                 <td class="w-1/5 !p-2.5">Konec účinnosti</td>
-                <td class="w-4/5 !p-2.5">{{ contract.valid_end_date }}</td>
+                <td class="w-4/5 !p-2.5">
+                    {% if contract.valid_end_date %}
+                        {{ contract.valid_end_date }}
+                    {% else %}
+                        <span class="text-grey-200">Neurčitý</span>
+                    {% endif %}
+                </td>
             </tr>
         </tbody>
     </table>
@@ -100,6 +106,21 @@
                 <td class="w-1/5 !p-2.5">Stav</td>
                 <td class="w-4/5 !p-2.5">{{ contract.get_paper_form_state_display }}</td>
             </tr>
+            <tr>
+                <td class="w-1/5 !p-2.5">Spisovna</td>
+                <td class="w-4/5 !p-2.5">
+                    <div class="flex gap-3 items-center">
+                        <div class="flex">
+                            {% include "contracts/includes/tag.html" with url="#TODO" icon="ico--drawer" content=contract.filing_area.name %}
+                        </div>
+                        <span>|</span>
+                        <span>
+                            zodpovědná osoba
+                            {{ contract.filing_area.person_responsible }}
+                        </span>
+                    </div>
+                </td>
+            </tr>
         </tbody>
     </table>
     
@@ -214,14 +235,15 @@
 
     {% with contract.contractee_signatures.all as signatures %}
         {% if signatures|length != 0 %}
-            <ul class="mb-5 grid grid-cols-3 gap-2">
+            <ul class="mb-5 grid grid-cols-2 gap-2">
                 {% for signature in signatures %}
                     <li class="p-3 border border-gray-300 rounded-md">
                         <address class="mb-3">
                             <div class="mb-1">
                                 <a
-                                    class="inline-block p-1.5 mb-1 rounded-sm whitespace-nowrap cursor-pointer not-italic hover:no-underline bg-gray-200 duration-100 hover:bg-gray-300"
+                                    class="inline-block p-1.5 mb-1 rounded-sm cursor-pointer not-italic hover:no-underline bg-gray-200 duration-100 hover:bg-gray-300"
                                 >
+                                    <i class="ico--office mr-2"></i>
                                     <strong>{{ signature.contractee.name }}</strong>
                                     {% if signature.contractee.department %}
                                         - {{ signature.contractee.department }}
@@ -266,14 +288,15 @@
 
     {% with contract.signee_signatures.all as signatures %}
         {% if signatures|length != 0 %}
-            <ul class="mb-5 grid grid-cols-3 gap-2">
+            <ul class="mb-5 grid grid-cols-2 gap-2">
                 {% for signature in signatures %}
                     <li class="p-3 border border-gray-300 rounded-md">
                         <address class="mb-3">
                             <div class="mb-1">
                                 <a
-                                    class="inline-block p-1.5 mb-1 rounded-sm whitespace-nowrap cursor-pointer not-italic hover:no-underline bg-gray-200 duration-100 hover:bg-gray-300"
+                                    class="inline-block p-1.5 mb-1 rounded-sm cursor-pointer not-italic hover:no-underline bg-gray-200 duration-100 hover:bg-gray-300"
                                 >
+                                    <i class="{% if signature.signee.entity_type == signature.signee.EntityTypes.LEGAL_ENTITY or signature.signee.entity_type == signature.signee.EntityTypes.OTHER %}ico--office{% else %}ico--user{% endif %} mr-2"></i>
                                     <strong>{{ signature.signee.name }}</strong>
                                     {% if signature.signee.department %}
                                         - {{ signature.signee.department }}
diff --git a/static_src/admin/contract_file_form.js b/static_src/admin/contract_file_form.js
new file mode 100644
index 0000000..38f8477
--- /dev/null
+++ b/static_src/admin/contract_file_form.js
@@ -0,0 +1,12 @@
+import $ from "jquery";
+
+$(window).ready(
+    () => {
+        $("body").append(
+            `<datalist id="file-types">
+    <option value="Původní verze">
+    <option value="Anonymizovaná verze">
+</datalist>`
+        );
+    }
+);
diff --git a/static_src/admin/signee_form.js b/static_src/admin/signee_form.js
index d03c7b5..bb19138 100644
--- a/static_src/admin/signee_form.js
+++ b/static_src/admin/signee_form.js
@@ -1,25 +1,70 @@
 import $ from "jquery";
 
+const fieldDepartmentValues = new Set([
+    "legal_entity",
+    "other",
+]);
+
 $(window).ready(
     () => {
+        let isPhysicalPerson = ($("#id_entity_type").find(":selected").val() === "natural_person");
+        let isEmpty = ($("#id_entity_type").find(":selected").val() === "");
+        
         $(".field-date_of_birth").
         css(
             "display",
             (
-                ($("#id_is_legal_entity").is(":checked")) ?
-                "none": "block"
+                (!isEmpty && isPhysicalPerson) ?
+                "block" : "none"
+            )
+        );
+        $(".field-ico_number").
+        css(
+            "display",
+            (
+                (!isEmpty && !isPhysicalPerson) ?
+                "block" : "none"
+            )
+        );
+        
+        $(".field-department").
+        css(
+            "display",
+            (
+                (!isEmpty && fieldDepartmentValues.has($("#id_entity_type").find(":selected").val())) ?
+                "block" : "none"
             )
         );
 
-        $("#id_is_legal_entity").on(
+        $("#id_entity_type").on(
             "change",
             event => {
+                isEmpty = ($(event.target).val() === "");
+                isPhysicalPerson = ($(event.target).val() === "natural_person");
+                
                 $(".field-date_of_birth").
                 css(
                     "display",
                     (
-                        (event.target.checked) ?
-                        "none" : "block"
+                        (!isEmpty && isPhysicalPerson) ?
+                        "block" : "none"
+                    )
+                );
+                $(".field-ico_number").
+                css(
+                    "display",
+                    (
+                        (!isEmpty && !isPhysicalPerson) ?
+                        "block" : "none"
+                    )
+                );
+                
+                $(".field-department").
+                css(
+                    "display",
+                    (
+                        (!isEmpty && fieldDepartmentValues.has($(event.target).val())) ?
+                        "block" : "none"
                     )
                 );
             }
diff --git a/webpack.config.js b/webpack.config.js
index ed6269a..36fbd6c 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -13,6 +13,10 @@ module.exports = {
       import: path.resolve("static_src", "admin", "contract_form.js"),
       dependOn: "shared",
     },
+    admin_contract_file_form: {
+      import: path.resolve("static_src", "admin", "contract_file_form.js"),
+      dependOn: "shared",
+    },
     admin_signee_form: {
       import: path.resolve("static_src", "admin", "signee_form.js"),
       dependOn: "shared",
-- 
GitLab