diff --git a/.gitignore b/.gitignore
index f62c1749..77ade033 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,3 +86,4 @@ local_settings.py
db.sqlite3
.vscode/
tmp/*
+node_modules/
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ff4a7366..7973a207 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -11,16 +11,17 @@
# pre-commit run --all-files
#
repos:
-- repo: https://github.com/pre-commit/pre-commit-hooks
+ - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- - id: trailing-whitespace
- - id: end-of-file-fixer
- - id: check-yaml
- - id: check-added-large-files
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - id: check-added-large-files
-# TODO: Enable black after formatting is standardized.
-# - repo: https://github.com/psf/black
-# rev: 22.10.0
-# hooks:
-# - id: black
+
+ - repo: https://github.com/psf/black
+ rev: 22.10.0
+ hooks:
+ - id: black
+ language_version: python3.11
diff --git a/afb-vite/afb/__init__.py b/afb-vite/afb/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/afb-vite/afb/asgi.py b/afb-vite/afb/asgi.py
new file mode 100644
index 00000000..78517635
--- /dev/null
+++ b/afb-vite/afb/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for afb project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "afb.settings")
+
+application = get_asgi_application()
diff --git a/afb-vite/afb/settings.py b/afb-vite/afb/settings.py
new file mode 100644
index 00000000..443ba6cf
--- /dev/null
+++ b/afb-vite/afb/settings.py
@@ -0,0 +1,208 @@
+"""
+Django settings for afb project.
+
+Generated by 'django-admin startproject' using Django 4.2.4.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/4.2/ref/settings/
+"""
+
+from pathlib import Path
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = "django-insecure-k3nma!u)7oz(lt346n-=rx=rt%u_^j8-rdz3p(y3o$ot0%soqh"
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+# http://127.0.0.1:8000/static/src/assets/logo.png
+
+INSTALLED_APPS = [
+ "unfold", # https://github.com/unfoldadmin/django-unfold
+ "django.contrib.admin",
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.messages",
+ "django.contrib.staticfiles",
+ "phonenumber_field",
+ "crispy_forms",
+ # 'tailwind',
+ "django_vite",
+ "crispy_tailwind",
+ # 'theme', # python manage.py tailwind init
+ "afbcore",
+ "django_browser_reload",
+]
+
+# correspond to your build.outDir in your ViteJS configuration.
+DJANGO_VITE_ASSETS_PATH = BASE_DIR / "ui" / "dist"
+
+# ViteJS webserver protocol (default : http).
+DJANGO_VITE_DEV_SERVER_PROTOCOL = "http"
+
+# ViteJS webserver hostname (default : localhost).
+DJANGO_VITE_DEV_SERVER_HOST = "127.0.0.1"
+
+# ViteJS webserver port (default : 3000)
+DJANGO_VITE_DEV_SERVER_PORT = "3000"
+
+# assets are included as modules using the ViteJS webserver. This will enable HMR for your assets.
+DJANGO_VITE_DEV_MODE = True
+
+# ViteJS webserver path to the HMR client used in the vite_hmr_client tag (default : @vite/client).
+DJANGO_VITE_WS_CLIENT_URL = "@vite/client"
+
+# Absolute path (including filename) to your ViteJS manifest file. This
+# file is generated in your DJANGO_VITE_ASSETS_PATH. But if you are in
+# production (DEBUG is false) then it is in your STATIC_ROOT after you
+# collected your static files (supports pathlib.Path or str).
+DJANGO_VITE_MANIFEST_PATH = DJANGO_VITE_ASSETS_PATH / "manifest.json"
+
+# prefix directory of your static files built by Vite. (default : "")
+# Use it if you want to avoid conflicts with other static files in your project.
+DJANGO_VITE_STATIC_URL_PREFIX = ""
+
+VITE_INPUT_CSS = "input.css"
+VITE_OUTPUT_CSS = "output.css"
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-STATIC_ROOT
+# https://docs.djangoproject.com/en/4.2/howto/static-files/#deployment
+# This should be an initially empty destination directory. it is not a place to
+# store your static files permanently.
+STATIC_ROOT = BASE_DIR / "staticfiles"
+
+# For prod:
+# https://docs.djangoproject.com/en/4.2/howto/static-files/deployment/#staticfiles-from-cdn
+# https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-STORAGES
+STATIC_URL = "static/"
+
+STATICFILES_DIRS = [
+ BASE_DIR / "static",
+ BASE_DIR / "ui" / "dist",
+ BASE_DIR / "ui" / "public",
+ DJANGO_VITE_ASSETS_PATH,
+]
+
+
+# https://github.com/django-crispy-forms/crispy-tailwind
+CRISPY_ALLOWED_TEMPLATE_PACKS = "tailwind"
+
+CRISPY_TEMPLATE_PACK = "tailwind"
+
+
+PHONENUMBER_DB_FORMAT = "INTERNATIONAL"
+PHONENUMBER_DEFAULT_FORMAT = "E164"
+PHONENUMBER_DEFAULT_REGION = "CA"
+
+
+MIDDLEWARE = [
+ "django.middleware.security.SecurityMiddleware",
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.middleware.common.CommonMiddleware",
+ "django.middleware.csrf.CsrfViewMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "django.contrib.messages.middleware.MessageMiddleware",
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
+ "django_browser_reload.middleware.BrowserReloadMiddleware",
+]
+
+ROOT_URLCONF = "afb.urls"
+
+# Django-Tailwind
+# https://django-tailwind.readthedocs.io/en/latest/installation.html#configuration
+
+# TAILWIND_APP_NAME = "theme"
+
+AUTH_USER_MODEL = "afbcore.User"
+
+INTERNAL_IPS = [
+ # Add local IP addresses here for tailwind to work, then run:
+ # * (Dev) `python manage.py tailwind install`
+ # * (Production) `python manage.py tailwind build`
+ "127.0.0.1",
+]
+
+# Templates
+# https://docs.djangoproject.com/en/4.2/ref/settings/#templates
+
+TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [],
+ "APP_DIRS": True,
+ "OPTIONS": {
+ "context_processors": [
+ "django.template.context_processors.debug",
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = "afb.wsgi.application"
+
+
+# Database
+# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
+
+DATABASES = {
+ "default": {
+ "ENGINE": "django.db.backends.sqlite3",
+ "NAME": BASE_DIR / "db.sqlite3",
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/4.2/topics/i18n/
+
+LANGUAGE_CODE = "en-us"
+
+TIME_ZONE = "UTC"
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
diff --git a/afb-vite/afb/urls.py b/afb-vite/afb/urls.py
new file mode 100644
index 00000000..bb973e02
--- /dev/null
+++ b/afb-vite/afb/urls.py
@@ -0,0 +1,34 @@
+"""
+URL configuration for afb project.
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/4.2/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.urls import include, path
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import include, path
+
+from afbcore.views import AboutView, ClientSignupFormView, DashboardView, MyLoginView
+from afbcore.views import ClientRequestView
+
+urlpatterns = [
+ path("admin/", admin.site.urls),
+ path("dashboard", DashboardView.as_view(), name="dashboard"),
+ path("", DashboardView.as_view()),
+ path("join/", ClientSignupFormView.as_view()),
+ # Part of django-tailwind
+ # See https://django-tailwind.readthedocs.io/en/latest/installation.html#configuration
+ path("__reload__/", include("django_browser_reload.urls")),
+ path("request/", ClientRequestView.as_view(), name="create_request"),
+ path("login/", MyLoginView.as_view(), name="login"),
+ path("about/", AboutView.as_view()),
+]
diff --git a/afb-vite/afb/wsgi.py b/afb-vite/afb/wsgi.py
new file mode 100644
index 00000000..cf57b0a4
--- /dev/null
+++ b/afb-vite/afb/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for afb project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "afb.settings")
+
+application = get_wsgi_application()
diff --git a/afb-vite/afbcore/__init__.py b/afb-vite/afbcore/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/afb-vite/afbcore/admin.py b/afb-vite/afbcore/admin.py
new file mode 100644
index 00000000..f0f74f60
--- /dev/null
+++ b/afb-vite/afbcore/admin.py
@@ -0,0 +1,11 @@
+from django.contrib import admin
+from django.contrib.auth.admin import UserAdmin
+from .models import Client, Manager, Volunteer, User
+
+admin.site.register(User, UserAdmin)
+admin.site.register(Client)
+admin.site.register(Manager)
+admin.site.register(Volunteer)
+
+
+# Register your models here.
diff --git a/afb-vite/afbcore/apps.py b/afb-vite/afbcore/apps.py
new file mode 100644
index 00000000..9f45ff80
--- /dev/null
+++ b/afb-vite/afbcore/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class AfbcoreConfig(AppConfig):
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "afbcore"
diff --git a/afb-vite/afbcore/forms/__init__.py b/afb-vite/afbcore/forms/__init__.py
new file mode 100644
index 00000000..a1387c1f
--- /dev/null
+++ b/afb-vite/afbcore/forms/__init__.py
@@ -0,0 +1,10 @@
+#
+
+from django import forms
+
+from .client import ClientSignupForm
+
+
+class LoginForm(forms.Form):
+ username = forms.CharField(max_length=100)
+ password = forms.CharField(widget=forms.PasswordInput)
diff --git a/afb-vite/afbcore/forms/client.py b/afb-vite/afbcore/forms/client.py
new file mode 100644
index 00000000..7a8ac2fd
--- /dev/null
+++ b/afb-vite/afbcore/forms/client.py
@@ -0,0 +1,16 @@
+from django.forms import ModelForm
+
+from afbcore.models import Client
+
+
+class ClientSignupForm(ModelForm):
+ class Meta:
+ model = Client
+ fields = [
+ "first_name",
+ "last_name",
+ "email",
+ "address",
+ "phone_number",
+ # "status",
+ ]
diff --git a/afb-vite/afbcore/migrations/0001_initial.py b/afb-vite/afbcore/migrations/0001_initial.py
new file mode 100644
index 00000000..2634d148
--- /dev/null
+++ b/afb-vite/afbcore/migrations/0001_initial.py
@@ -0,0 +1,524 @@
+# Generated by Django 4.2.5 on 2023-09-22 02:58
+
+from django.conf import settings
+import django.contrib.auth.models
+import django.contrib.auth.validators
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+import phonenumber_field.modelfields
+import uuid
+
+
+class Migration(migrations.Migration):
+ initial = True
+
+ dependencies = [
+ ("auth", "0012_alter_user_first_name_max_length"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="User",
+ fields=[
+ ("password", models.CharField(max_length=128, verbose_name="password")),
+ (
+ "last_login",
+ models.DateTimeField(
+ blank=True, null=True, verbose_name="last login"
+ ),
+ ),
+ (
+ "is_superuser",
+ models.BooleanField(
+ default=False,
+ help_text="Designates that this user has all permissions without explicitly assigning them.",
+ verbose_name="superuser status",
+ ),
+ ),
+ (
+ "username",
+ models.CharField(
+ error_messages={
+ "unique": "A user with that username already exists."
+ },
+ help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
+ max_length=150,
+ unique=True,
+ validators=[
+ django.contrib.auth.validators.UnicodeUsernameValidator()
+ ],
+ verbose_name="username",
+ ),
+ ),
+ (
+ "first_name",
+ models.CharField(
+ blank=True, max_length=150, verbose_name="first name"
+ ),
+ ),
+ (
+ "last_name",
+ models.CharField(
+ blank=True, max_length=150, verbose_name="last name"
+ ),
+ ),
+ (
+ "email",
+ models.EmailField(
+ blank=True, max_length=254, verbose_name="email address"
+ ),
+ ),
+ (
+ "is_staff",
+ models.BooleanField(
+ default=False,
+ help_text="Designates whether the user can log into this admin site.",
+ verbose_name="staff status",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
+ verbose_name="active",
+ ),
+ ),
+ (
+ "date_joined",
+ models.DateTimeField(
+ default=django.utils.timezone.now, verbose_name="date joined"
+ ),
+ ),
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ (
+ "groups",
+ models.ManyToManyField(
+ blank=True,
+ help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
+ related_name="user_set",
+ related_query_name="user",
+ to="auth.group",
+ verbose_name="groups",
+ ),
+ ),
+ (
+ "user_permissions",
+ models.ManyToManyField(
+ blank=True,
+ help_text="Specific permissions for this user.",
+ related_name="user_set",
+ related_query_name="user",
+ to="auth.permission",
+ verbose_name="user permissions",
+ ),
+ ),
+ ],
+ options={
+ "verbose_name": "user",
+ "verbose_name_plural": "users",
+ "abstract": False,
+ },
+ managers=[
+ ("objects", django.contrib.auth.models.UserManager()),
+ ],
+ ),
+ migrations.CreateModel(
+ name="Branch",
+ fields=[
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ (
+ "location_name",
+ models.CharField(
+ help_text="ie Winnipeg, MB; Medicine Hat, AB etc.",
+ max_length=255,
+ ),
+ ),
+ ("frequency_of_requests", models.CharField(max_length=255)),
+ ("spay_neuter_requirement", models.BooleanField(default=False)),
+ ("pets_per_household_max", models.IntegerField(default=4)),
+ ("pickup_locations", models.TextField()),
+ ("delivery_deadline_days", models.IntegerField(default=3)),
+ (
+ "delivery_type",
+ models.CharField(
+ choices=[("drop_off", "Drop off"), ("pick_up", "Pick up")],
+ default="Drop off",
+ max_length=24,
+ ),
+ ),
+ ("delivery_pickup_details", models.TextField(blank=True)),
+ ("blurb", models.TextField(blank=True)),
+ (
+ "blurb_image",
+ models.ImageField(
+ blank=True, null=True, upload_to="branch_images/"
+ ),
+ ),
+ ],
+ ),
+ migrations.CreateModel(
+ name="Client",
+ fields=[
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ ("first_name", models.CharField(max_length=64)),
+ ("last_name", models.CharField(max_length=64)),
+ ("email", models.EmailField(max_length=254, unique=True)),
+ (
+ "phone_number",
+ phonenumber_field.modelfields.PhoneNumberField(
+ blank=True, max_length=20, null=True, region="US"
+ ),
+ ),
+ ("address_verbatim", models.CharField(blank=True, max_length=255)),
+ ("address", models.CharField(max_length=255, null=True)),
+ ("validated_postal_code", models.CharField(max_length=20, null=True)),
+ ("country", models.CharField(blank=True, max_length=255)),
+ (
+ "status",
+ models.CharField(
+ choices=[
+ ("active", "Active"),
+ ("on_hold", "On Hold"),
+ ("banned", "Banned"),
+ ],
+ default="active",
+ max_length=20,
+ ),
+ ),
+ (
+ "branches",
+ models.ManyToManyField(
+ blank=True, related_name="+", to="afbcore.branch"
+ ),
+ ),
+ (
+ "user",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.DO_NOTHING,
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ options={
+ "abstract": False,
+ },
+ ),
+ migrations.CreateModel(
+ name="DeliveryRegion",
+ fields=[
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ help_text="Name of the region (e.g. postal code, city, or area)",
+ max_length=255,
+ ),
+ ),
+ ("description", models.TextField(blank=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name="FoodAvailable",
+ fields=[
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ ("name", models.CharField(max_length=255)),
+ (
+ "pet_type",
+ models.CharField(
+ choices=[("Cat", "Cat"), ("Dog", "Dog"), ("Other", "Other")],
+ max_length=255,
+ ),
+ ),
+ ("food_type", models.CharField(max_length=255)),
+ ("food_amount", models.CharField(max_length=255)),
+ ],
+ ),
+ migrations.CreateModel(
+ name="Pet",
+ fields=[
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ ("name", models.CharField(max_length=255)),
+ ("dob", models.DateField()),
+ (
+ "size",
+ models.CharField(
+ choices=[
+ ("TOY", "Toy - up to 10lbs"),
+ ("SMALL_BREED", "Small Breed - 10-20 lbs"),
+ ("MEDIUM_BREED", "Medium Breed - 20-50 lbs"),
+ ("LARGE_BREED", "Large Breed - 50-100 lbs"),
+ ("GIANT_BREED", "Giant Breed - 100+ lbs"),
+ ],
+ max_length=32,
+ ),
+ ),
+ (
+ "weight",
+ models.CharField(
+ choices=[
+ ("UP_TO_10_LBS", "Up to 10 lbs"),
+ ("FROM_10_TO_20_LBS", "10-20 lbs"),
+ ("FROM_20_TO_50_LBS", "20-50 lbs"),
+ ("FROM_50_TO_100_LBS", "50-100 lbs"),
+ ("OVER_100_LBS", "Over 100 lbs"),
+ ],
+ max_length=32,
+ ),
+ ),
+ ("usual_food_brands", models.TextField(blank=True)),
+ ("allergies", models.BooleanField(default=False)),
+ ("allergy_types", models.TextField(blank=True)),
+ (
+ "pictures",
+ models.ImageField(blank=True, null=True, upload_to="pet_pictures/"),
+ ),
+ (
+ "client",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE, to="afbcore.client"
+ ),
+ ),
+ ],
+ ),
+ migrations.CreateModel(
+ name="Volunteer",
+ fields=[
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ ("first_name", models.CharField(max_length=64)),
+ ("last_name", models.CharField(max_length=64)),
+ ("email", models.EmailField(max_length=254, unique=True)),
+ ("address_verbatim", models.CharField(blank=True, max_length=255)),
+ ("address", models.CharField(max_length=255, null=True)),
+ ("phone_number", models.CharField(max_length=20)),
+ ("points_earned", models.IntegerField(default=0)),
+ (
+ "branches",
+ models.ManyToManyField(
+ blank=True, related_name="+", to="afbcore.branch"
+ ),
+ ),
+ (
+ "delivery_regions",
+ models.ManyToManyField(to="afbcore.deliveryregion"),
+ ),
+ (
+ "user",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.DO_NOTHING,
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ options={
+ "abstract": False,
+ },
+ ),
+ migrations.CreateModel(
+ name="PetRequest",
+ fields=[
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ ("confirm_address", models.BooleanField()),
+ ("confirm_phone_number", models.BooleanField()),
+ ("agreed_to_terms", models.BooleanField()),
+ ("method_of_contact", models.CharField(max_length=100)),
+ ("date_requested", models.DateField(auto_now_add=True)),
+ ("safe_drop", models.BooleanField()),
+ ("request_notes", models.TextField(max_length=255)),
+ (
+ "status",
+ models.CharField(
+ choices=[
+ ("received", "Request Received"),
+ ("approved", "Request Approved & in Queue"),
+ ("denied", "Request Denied"),
+ ("assigned", "Volunteer Assigned"),
+ ("ready_for_pickup", "Request Ready For Volunteer Pickup"),
+ ("scheduled", "Delivery Scheduled"),
+ ("out_for_delivery", "Out For Delivery"),
+ ("delivered", "Delivered"),
+ ("undeliverable", "Undeliverable"),
+ ],
+ default="received",
+ max_length=20,
+ ),
+ ),
+ (
+ "driver_comments",
+ models.TextField(blank=True, max_length=255, null=True),
+ ),
+ (
+ "picture_of_delivery",
+ models.ImageField(
+ blank=True, null=True, upload_to="delivery_pictures/"
+ ),
+ ),
+ ("needs_review", models.BooleanField()),
+ (
+ "branch",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.DO_NOTHING,
+ to="afbcore.branch",
+ ),
+ ),
+ (
+ "client",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.DO_NOTHING,
+ to="afbcore.client",
+ ),
+ ),
+ (
+ "food_types_available",
+ models.ManyToManyField(to="afbcore.foodavailable"),
+ ),
+ ("pets", models.ManyToManyField(to="afbcore.pet")),
+ ],
+ options={
+ "ordering": ["-date_requested"],
+ },
+ ),
+ migrations.CreateModel(
+ name="Manager",
+ fields=[
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ ("first_name", models.CharField(max_length=64)),
+ ("last_name", models.CharField(max_length=64)),
+ ("email", models.EmailField(max_length=254, unique=True)),
+ (
+ "phone_number",
+ phonenumber_field.modelfields.PhoneNumberField(
+ blank=True, max_length=20, null=True, region="US"
+ ),
+ ),
+ ("address_verbatim", models.CharField(blank=True, max_length=255)),
+ ("address", models.CharField(max_length=255, null=True)),
+ ("role_level", models.IntegerField()),
+ (
+ "branches",
+ models.ManyToManyField(
+ blank=True, related_name="+", to="afbcore.branch"
+ ),
+ ),
+ (
+ "user",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.DO_NOTHING,
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ options={
+ "abstract": False,
+ },
+ ),
+ migrations.CreateModel(
+ name="Delivery",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("delivery_date", models.DateField()),
+ ("delivery_time", models.TimeField()),
+ ("delivery_address", models.CharField(max_length=255)),
+ (
+ "food_available",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.DO_NOTHING,
+ to="afbcore.foodavailable",
+ ),
+ ),
+ (
+ "pet_request",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.DO_NOTHING,
+ to="afbcore.petrequest",
+ ),
+ ),
+ ],
+ ),
+ migrations.AddField(
+ model_name="branch",
+ name="delivery_regions",
+ field=models.ManyToManyField(to="afbcore.deliveryregion"),
+ ),
+ ]
diff --git a/afb-vite/afbcore/migrations/__init__.py b/afb-vite/afbcore/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/afb-vite/afbcore/models/__init__.py b/afb-vite/afbcore/models/__init__.py
new file mode 100644
index 00000000..9e9b412e
--- /dev/null
+++ b/afb-vite/afbcore/models/__init__.py
@@ -0,0 +1,19 @@
+from django.db import models
+
+from .branch import Branch # noqa
+from .users import Client, Manager, Volunteer, User
+from .pet_request import PetRequest
+from .pet import Pet
+from .food_available import FoodAvailable
+from .delivery import Delivery, DeliveryRegion
+
+"""
+# https://docs.trunk.io/check/ignoring-issues
+Branch
+Profile
+Manager
+Client
+Volunteer
+Pet
+HelpRequest
+"""
diff --git a/afb-vite/afbcore/models/branch.py b/afb-vite/afbcore/models/branch.py
new file mode 100644
index 00000000..483a35aa
--- /dev/null
+++ b/afb-vite/afbcore/models/branch.py
@@ -0,0 +1,56 @@
+import uuid
+
+from django.db import models
+
+
+class Branch(models.Model):
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+
+ # Location Name ie Winnipeg, MB; Medicine Hat, AB etc.
+ location_name = models.CharField(
+ max_length=255, help_text="ie Winnipeg, MB; Medicine Hat, AB etc."
+ )
+
+ # Postal/Zip Code Range start with Canada but the intent is to
+ # use this in the USA which may be more apt to paying
+ # postal_zip_code_range = models.CharField(max_length=255)
+ delivery_regions = models.ManyToManyField("DeliveryRegion")
+
+ # Frequency of Requests Weeks, Month, Months. This would need to be able
+ # to be edited, as we do change it sometimes.
+ frequency_of_requests = models.CharField(max_length=255)
+
+ # Spay/Neuter Requirement likely a yes or no? As in does that branch expect
+ # clients to spay/neuter their pets to gain access to the food bank?
+ spay_neuter_requirement = models.BooleanField(default=False)
+
+ # Number of Pets serviced/Household. We set this as four but it may be nice, in future, to be able to edit it based on a regions bylaws.
+ pets_per_household_max = models.IntegerField(default=4)
+
+ # Delivery Deadline. For example, Winnipeg is 14 days
+ delivery_deadline_days = models.IntegerField()
+
+ # Pickup Locations not sure about this one, but in Winnipeg for instance we have various spots to pick up inventory and those locations can change (they are volunteers houses). When drivers sign up for a delivery they choose the location they want to pick up from.
+ pickup_locations = models.TextField()
+
+ # Delivery Type Drop off and/or pick up options
+ delivery_type = models.CharField(max_length=255)
+
+ # Delivery deadline in days
+ delivery_deadline_days = models.IntegerField(default=3)
+
+ # Type of delivery service, 'Drop off' or 'Pick up'
+ delivery_type = models.CharField(
+ max_length=24,
+ choices=[("drop_off", "Drop off"), ("pick_up", "Pick up")],
+ default="Drop off",
+ )
+
+ # Delivery/pickup More details
+ delivery_pickup_details = models.TextField(blank=True)
+
+ # Blurb An optional text field for a short intro or description etc.
+ blurb = models.TextField(blank=True)
+
+ # Blurb image A picture to go along with the blurb
+ blurb_image = models.ImageField(upload_to="branch_images/", blank=True, null=True)
diff --git a/afb-vite/afbcore/models/client.py b/afb-vite/afbcore/models/client.py
new file mode 100644
index 00000000..7a8ac2fd
--- /dev/null
+++ b/afb-vite/afbcore/models/client.py
@@ -0,0 +1,16 @@
+from django.forms import ModelForm
+
+from afbcore.models import Client
+
+
+class ClientSignupForm(ModelForm):
+ class Meta:
+ model = Client
+ fields = [
+ "first_name",
+ "last_name",
+ "email",
+ "address",
+ "phone_number",
+ # "status",
+ ]
diff --git a/afb-vite/afbcore/models/delivery.py b/afb-vite/afbcore/models/delivery.py
new file mode 100644
index 00000000..4082928d
--- /dev/null
+++ b/afb-vite/afbcore/models/delivery.py
@@ -0,0 +1,28 @@
+import uuid
+from django.db import models
+
+
+class DeliveryRegion(models.Model):
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+
+ name = models.CharField(
+ max_length=255, help_text="Name of the region (e.g. postal code, city, or area)"
+ )
+ description = models.TextField(blank=True)
+
+ def __str__(self):
+ return self.name
+
+
+class Delivery(models.Model):
+ pet_request = models.ForeignKey("PetRequest", on_delete=models.DO_NOTHING)
+
+ food_available = models.ForeignKey("FoodAvailable", on_delete=models.DO_NOTHING)
+
+ delivery_date = models.DateField()
+ delivery_time = models.TimeField()
+
+ delivery_address = models.CharField(max_length=255)
+
+ def __str__(self):
+ return f"{self.client} - {self.delivery_date}"
diff --git a/afb-vite/afbcore/models/food_available.py b/afb-vite/afbcore/models/food_available.py
new file mode 100644
index 00000000..520b412b
--- /dev/null
+++ b/afb-vite/afbcore/models/food_available.py
@@ -0,0 +1,47 @@
+"""This module defines the FoodAvailable model."""
+
+import uuid
+
+from django.db import models
+from enum import Enum
+
+
+class PetType(Enum):
+ CAT = "Cat"
+ DOG = "Dog"
+ OTHER = "Other"
+
+
+class FoodAvailable(models.Model):
+ """
+ Needs to support fields for different types of pets (e.g. cats, dogs, and other pets), as well as different types of food (e.g. dry and wet) and different amounts of food based on the size of the pet.
+
+ Example of records that will need to be created.
+
+ Cats
+ Dry 1.25 lbs/cat/week
+ Wet 6-12 cans if we have it
+ Dogs
+ Dry
+ Toy 1.25 lbs/week
+ Small Breed 3.5 lbs/week
+ Medium Breed 6 lbs /week
+ Large Breed 10 lbs/week
+ Giant Breed 12.5 lbs/week
+ Wet 6-12 cans if we have it
+
+ Any other pet type No estimate
+ Total Cat Dry
+ Total Cat Wet
+ Total Dog Dry
+ Total Dog Wet
+ """
+
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+ name = models.CharField(max_length=255)
+ pet_type = models.CharField(
+ max_length=255,
+ choices=[(pet_type.value, pet_type.value) for pet_type in PetType],
+ )
+ food_type = models.CharField(max_length=255)
+ food_amount = models.CharField(max_length=255)
diff --git a/afb-vite/afbcore/models/pet.py b/afb-vite/afbcore/models/pet.py
new file mode 100644
index 00000000..ed6faa2a
--- /dev/null
+++ b/afb-vite/afbcore/models/pet.py
@@ -0,0 +1,68 @@
+import uuid
+
+from enum import Enum
+from django.db import models
+
+
+class PetSize(Enum):
+ TOY = "Toy - up to 10lbs"
+ SMALL_BREED = "Small Breed - 10-20 lbs"
+ MEDIUM_BREED = "Medium Breed - 20-50 lbs"
+ LARGE_BREED = "Large Breed - 50-100 lbs"
+ GIANT_BREED = "Giant Breed - 100+ lbs"
+
+
+class WeightRange(Enum):
+ UP_TO_10_LBS = "Up to 10 lbs"
+ FROM_10_TO_20_LBS = "10-20 lbs"
+ FROM_20_TO_50_LBS = "20-50 lbs"
+ FROM_50_TO_100_LBS = "50-100 lbs"
+ OVER_100_LBS = "Over 100 lbs"
+
+
+class Pet(models.Model):
+
+ """
+ Pet model to store information about pets belonging to clients.
+
+ The maximum number of pet profiles that would be allowed
+ to be created would be deteremined from the Branch
+ setting of "Number of Pet's Serviced/Houeshold" above
+
+ """
+
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+
+ # Client - Foreign Key
+ client = models.ForeignKey("Client", on_delete=models.CASCADE)
+
+ # Name
+ name = models.CharField(max_length=255)
+
+ # DOB - I'd like to system to record the date of birth and then use it to calculate real time age
+ dob = models.DateField()
+
+ # Size - Drop down list with size options
+ size = models.CharField(
+ max_length=32, choices=[(size.name, size.value) for size in PetSize]
+ )
+
+ # Weight - Drop down list with weight ranges (this is typically only needed for dogs). Select one.
+ weight = models.CharField(
+ max_length=32, choices=[(size.name, size.value) for size in WeightRange]
+ )
+
+ # Usual Food Brands - Free form
+ usual_food_brands = models.TextField(blank=True)
+
+ # Allergies - Yes/No
+ allergies = models.BooleanField(default=False)
+
+ # Allergies Type - Drop down list with an "other" option that is free form text. Select all that apply
+ allergy_types = models.TextField(blank=True)
+
+ # Pictures - For no reason other than I think it would be fun to have their client dashboard have pics of their pets for the profiles
+ pictures = models.ImageField(upload_to="pet_pictures/", null=True, blank=True)
+
+ def __str__(self):
+ return self.name
diff --git a/afb-vite/afbcore/models/pet_request.py b/afb-vite/afbcore/models/pet_request.py
new file mode 100644
index 00000000..6f5818dd
--- /dev/null
+++ b/afb-vite/afbcore/models/pet_request.py
@@ -0,0 +1,73 @@
+# PetRequest
+
+import uuid
+
+from django.db import models
+
+
+STATUS_CHOICES = [
+ ("received", "Request Received"),
+ ("approved", "Request Approved & in Queue"),
+ ("denied", "Request Denied"),
+ ("assigned", "Volunteer Assigned"),
+ ("ready_for_pickup", "Request Ready For Volunteer Pickup"),
+ ("scheduled", "Delivery Scheduled"),
+ ("out_for_delivery", "Out For Delivery"),
+ ("delivered", "Delivered"),
+ ("undeliverable", "Undeliverable"),
+]
+
+
+class PetRequest(models.Model):
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+
+ client = models.ForeignKey("Client", on_delete=models.DO_NOTHING)
+
+ branch = models.ForeignKey("Branch", on_delete=models.DO_NOTHING)
+
+ # One or more. ** We will want them to see and confirm/edit their address and phone number on the request, and be able to see pets, and edit some fields of their pets info
+ pets = models.ManyToManyField("Pet")
+
+ # Yes/No - No requires them to edit address and ensure that it's not attached to another client or then both clients need to be on hold to review
+ confirm_address = models.BooleanField()
+
+ # Yes/No - No requires them to update phone number (validate format)
+ confirm_phone_number = models.BooleanField()
+
+ # Agree to Terms and Conditions
+ agreed_to_terms = models.BooleanField()
+
+ # Text or Phone
+ method_of_contact = models.CharField(max_length=100)
+
+ # Drop down list with an "other" option that is free form text. Select all that apply.
+ food_types_available = models.ManyToManyField("FoodAvailable")
+
+ # Use system date - do not let clients input/edit. We like to have deliveries made within the branches delivery window so would be great if we could send notifications when requests are "aging"
+ date_requested = models.DateField(auto_now_add=True)
+
+ # Yes/No
+ safe_drop = models.BooleanField()
+
+ # Free form comments from client - set max character limit
+ request_notes = models.TextField(max_length=255)
+
+ # Request Received, Request Approved & in Queue, Request Denied, Volunteer Assigned, Request Ready For Volunteer Pickup, Delivery Scheduled, Out For Delivery, Delivered, Undeliverable
+ status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="received")
+
+ # Driver comments
+ driver_comments = models.TextField(max_length=255, null=True, blank=True)
+
+ # Picture of delivery
+ picture_of_delivery = models.ImageField(
+ upload_to="delivery_pictures/", null=True, blank=True
+ )
+
+ # Not sure what to call this one, but if the volunteer has an issue with the client - they are rude or aggressive for example, can we allow the driver to mark the client as suspended and admin to review?
+ needs_review = models.BooleanField()
+
+ def __str__(self):
+ return f"Pet Request {self.id}"
+
+ class Meta:
+ ordering = ["-date_requested"]
diff --git a/afb-vite/afbcore/models/users/__init__.py b/afb-vite/afbcore/models/users/__init__.py
new file mode 100644
index 00000000..4bd242ef
--- /dev/null
+++ b/afb-vite/afbcore/models/users/__init__.py
@@ -0,0 +1,5 @@
+from .client import Client
+from .manager import Manager
+from .volunteer import Volunteer
+from .base_profile import BaseProfile
+from .user import User
diff --git a/afb-vite/afbcore/models/users/base_profile.py b/afb-vite/afbcore/models/users/base_profile.py
new file mode 100644
index 00000000..00420417
--- /dev/null
+++ b/afb-vite/afbcore/models/users/base_profile.py
@@ -0,0 +1,57 @@
+import uuid
+
+from django.db import models
+
+# https://django-phonenumber-field.readthedocs.io/en/latest/reference.html#model-field
+# https://github.com/google/libphonenumber/blob/master/FALSEHOODS.md
+from phonenumber_field.modelfields import PhoneNumberField
+
+from .user import User
+
+# Define default arguments for ManyToManyField
+many_to_many_defaults = {
+ "related_name": "+",
+ "blank": True,
+ "symmetrical": False,
+}
+
+
+class BaseProfile(models.Model):
+ class Meta:
+ abstract = True
+
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+
+ user = models.OneToOneField(User, on_delete=models.DO_NOTHING)
+
+ # Usually just one, but can be multiple
+ branches = models.ManyToManyField("Branch", **many_to_many_defaults)
+
+ # First Name
+ first_name = models.CharField(max_length=64)
+
+ # Last Name
+ last_name = models.CharField(max_length=64)
+
+ # Email - Unique - don't allow duplicates.
+ email = models.EmailField(unique=True)
+
+ # Phone - Validate format - numbers only
+ phone_number = PhoneNumberField(
+ blank=True,
+ null=True,
+ region="US",
+ max_length=20,
+ )
+
+ # We allow free form text entry but store the validated
+ # address in the `address` field. These fields should
+ # generally be updated together.
+ #
+ # e.g. A client may enter "123 Main St" and another
+ # client may enter "123 Main Street"
+ address_verbatim = models.CharField(max_length=255, blank=True)
+
+ # Validated Address
+ # i.e. An address from Canada Post or Google Maps
+ address = models.CharField(max_length=255, null=True)
diff --git a/afb-vite/afbcore/models/users/client.py b/afb-vite/afbcore/models/users/client.py
new file mode 100644
index 00000000..790c4102
--- /dev/null
+++ b/afb-vite/afbcore/models/users/client.py
@@ -0,0 +1,41 @@
+import uuid
+
+from django.db import models
+from django.contrib.auth.models import AbstractUser
+from django.urls import reverse
+
+from .base_profile import BaseProfile
+
+# Status - Active, On Hold, Banned
+STATUS_CHOICES = [
+ ("active", "Active"),
+ ("on_hold", "On Hold"),
+ ("banned", "Banned"),
+]
+
+
+class Client(BaseProfile):
+
+ """
+ Clients could try to scam and create duplicate accounts to circumvent frequency, change pet info, etc.
+ We need to do our best to ensure each account is unique.
+ """
+
+ # Address - If address is duplicate to another clients, both accounts need to be placed on hold and manually reviewed/approved bc people are scammers.
+ # Has to be a validated address (google?) and not permitted to be overwritten. The last amount of free form text entry as possible.
+ # You'd be amazed how many clients don't know their postal code and we route by postal code sooooo
+
+ # Postal/Zip Code - Has to be a validated address (google?) and not permitted to be overwritten. The last amount of free form text entry as possible.
+ # You'd be amazed how many clients don't know their postal code and we route by postal code sooooo
+ validated_postal_code = models.CharField(max_length=20, null=True)
+
+ # Country - I don't know if we need this but google addresses populate country too. It may be useful for analytics
+ country = models.CharField(max_length=255, blank=True)
+
+ status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="active")
+
+ def __str__(self):
+ return f"{self.first_name} {self.last_name}"
+
+ def get_absolute_url(self):
+ return reverse("client-create", kwargs={"pk": self.pk})
diff --git a/afb-vite/afbcore/models/users/manager.py b/afb-vite/afbcore/models/users/manager.py
new file mode 100644
index 00000000..a7e8ac83
--- /dev/null
+++ b/afb-vite/afbcore/models/users/manager.py
@@ -0,0 +1,38 @@
+import uuid
+
+from django.db import models
+
+from .base_profile import BaseProfile
+
+
+class Manager(BaseProfile):
+ """ """
+
+ role_level = models.IntegerField()
+
+ def __str__(self):
+ return f"{self.first_name} {self.last_name}"
+
+
+"""
+GitHub Copilot: Here are all the arguments that can be used with Django's `ManyToManyField`:
+
+- `to`: The model to which the relationship is defined. This can be a string containing the name of the model, or the model class itself.
+- `related_name`: The name to use for the reverse relation from the related object back to this one. This is used to access the related objects from the other side of the relationship.
+- `related_query_name`: The name to use for the reverse relation from the related object back to this one when performing queries. This is used to filter the related objects from the other side of the relationship.
+- `limit_choices_to`: A dictionary of lookup arguments to use when limiting the available choices for the relationship.
+- `symmetrical`: A boolean indicating whether the relationship is symmetrical. This is used when the relationship is defined on both sides of the model.
+- `through`: The intermediate model to use for the relationship. This is used when you need to add extra fields to the relationship.
+- `through_fields`: A tuple of field names that specify the fields on the intermediate model that should be used for the relationship.
+- `db_table`: The name of the database table to use for the relationship.
+- `db_constraint`: A boolean indicating whether to create a database constraint for the relationship.
+- `swappable`: A boolean indicating whether the relationship can be swapped out with another model.
+- `blank`: A boolean indicating whether the field is allowed to be blank.
+- `null`: A boolean indicating whether the field is allowed to be null.
+- `default`: The default value for the field.
+- `editable`: A boolean indicating whether the field is editable.
+- `help_text`: The help text to display for the field.
+- `verbose_name`: The human-readable name to use for the field.
+- `validators`: A list of validators to use for the field.
+- `error_messages`: A dictionary of error messages to use for the field.
+"""
diff --git a/afb-vite/afbcore/models/users/user.py b/afb-vite/afbcore/models/users/user.py
new file mode 100644
index 00000000..dd406742
--- /dev/null
+++ b/afb-vite/afbcore/models/users/user.py
@@ -0,0 +1,8 @@
+import uuid
+
+from django.db import models
+from django.contrib.auth.models import AbstractUser
+
+
+class User(AbstractUser):
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
diff --git a/afb-vite/afbcore/models/users/volunteer.py b/afb-vite/afbcore/models/users/volunteer.py
new file mode 100644
index 00000000..9ad4d68d
--- /dev/null
+++ b/afb-vite/afbcore/models/users/volunteer.py
@@ -0,0 +1,25 @@
+import uuid
+from django.db import models
+
+from .base_profile import BaseProfile
+
+
+class Volunteer(BaseProfile):
+
+ # Would love for the client and volunteer to be able to communicate through the software - and not have the volunteer have to use their personal phone to arrange delivery. However, we, as admin, need their phone number
+ phone_number = models.CharField(max_length=20)
+
+ # Postal/Zip Codes/Cities will deliver to
+ # We will use this to notify them of available deliveries in their "regions"
+ # TODO: Figure out how to do this. It could be a list of strings as a
+ # rudimentary approach, where the string could be a postal code, city,
+ # or region. Or it could be a list of foreign keys to a "DeliveryRegion"
+ # which would still be a simple string but reduce dupes.
+ delivery_regions = models.ManyToManyField("DeliveryRegion")
+
+ # Points/Rewards Earned
+ # For each delivery made/attempted - redeem these for swag/gift cards
+ points_earned = models.IntegerField(default=0)
+
+ def __str__(self):
+ return f"{self.first_name} {self.last_name}"
diff --git a/afb-vite/afbcore/templates/about.html b/afb-vite/afbcore/templates/about.html
new file mode 100644
index 00000000..bf2e2e66
--- /dev/null
+++ b/afb-vite/afbcore/templates/about.html
@@ -0,0 +1,11 @@
+
+{% extends 'appshell.html' %}
+
+{% block content %}
+
+
+About AFB
+
+
+
+{% endblock %}
diff --git a/afb-vite/afbcore/templates/afbcore/client_request.html b/afb-vite/afbcore/templates/afbcore/client_request.html
new file mode 100644
index 00000000..6931a3e7
--- /dev/null
+++ b/afb-vite/afbcore/templates/afbcore/client_request.html
@@ -0,0 +1,13 @@
+
+{% extends 'appshell.html' %}
+
+{% load tailwind_filters %}
+
+
+{% block content %}
+
+Make a request
+
+{{form | crispy}}
+
+{% endblock %}
diff --git a/afb-vite/afbcore/templates/afbcore/client_request_hardcoded_example.html b/afb-vite/afbcore/templates/afbcore/client_request_hardcoded_example.html
new file mode 100644
index 00000000..912038c2
--- /dev/null
+++ b/afb-vite/afbcore/templates/afbcore/client_request_hardcoded_example.html
@@ -0,0 +1,203 @@
+
+
+
+
diff --git a/afb-vite/afbcore/templates/afbcore/client_signup_form.html b/afb-vite/afbcore/templates/afbcore/client_signup_form.html
new file mode 100644
index 00000000..8880ded3
--- /dev/null
+++ b/afb-vite/afbcore/templates/afbcore/client_signup_form.html
@@ -0,0 +1,30 @@
+
+{% extends 'appshell.html' %}
+
+{% load static %}
+{% load tailwind_filters %}
+
+
+{% block contentHeader %}
+
+ Join
+
+{% endblock %}
+
+
+{% block content %}
+
+Create a client profile
+
+
+
+
+{% endblock %}
diff --git a/afb-vite/afbcore/templates/afbcore/login.html b/afb-vite/afbcore/templates/afbcore/login.html
new file mode 100644
index 00000000..93febf51
--- /dev/null
+++ b/afb-vite/afbcore/templates/afbcore/login.html
@@ -0,0 +1,10 @@
+{% extends 'appshell.html' %}
+
+{% block content %}
+ Login
+
+{% endblock %}
diff --git a/afb-vite/afbcore/templates/appshell.html b/afb-vite/afbcore/templates/appshell.html
new file mode 100644
index 00000000..272719d6
--- /dev/null
+++ b/afb-vite/afbcore/templates/appshell.html
@@ -0,0 +1,46 @@
+
+{% extends 'base.html' %}
+{% comment %} {% include "appshell.html" with person="Jane" greeting="Hello" %} {% endcomment %}
+
+{% comment "" %}
+https://tailwindui.com/components#product-application-ui-application-shells
+{% endcomment %}
+
+
+{% load static %}
+{% load tailwind_filters %}
+
+
+{% block title %}AFB{% endblock %}
+
+{% block metaContent %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
+
+{% block bodyContent %}
+
+
+
+ {% block content %}
+
+
+
+ {% endblock %}
+
+{% endblock %}
diff --git a/afb-vite/afbcore/templates/base.html b/afb-vite/afbcore/templates/base.html
new file mode 100644
index 00000000..1cdaccd4
--- /dev/null
+++ b/afb-vite/afbcore/templates/base.html
@@ -0,0 +1,29 @@
+
+{% load django_vite %}
+
+
+
+
+
+
+
+
+
+ {% block metaContent %}{% endblock %}
+
+ {% block title %}AFB{% endblock %}
+
+ {% vite_hmr_client %}
+ {% vite_asset 'src/main.ts' %}
+
+
+
+
+
+ {% block bodyContent %}
+
+
+ {% endblock %}
+
+
+
diff --git a/afb-vite/afbcore/templates/dashboard/client.html b/afb-vite/afbcore/templates/dashboard/client.html
new file mode 100644
index 00000000..8cfb86a1
--- /dev/null
+++ b/afb-vite/afbcore/templates/dashboard/client.html
@@ -0,0 +1,9 @@
+
+{% extends 'appshell.html' %}
+
+
+{% block contentHeader %}
+
+ Dashboard
+
+{% endblock %}
diff --git a/afb-vite/afbcore/tests.py b/afb-vite/afbcore/tests.py
new file mode 100644
index 00000000..7ce503c2
--- /dev/null
+++ b/afb-vite/afbcore/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/afb-vite/afbcore/views/__init__.py b/afb-vite/afbcore/views/__init__.py
new file mode 100644
index 00000000..868df5ee
--- /dev/null
+++ b/afb-vite/afbcore/views/__init__.py
@@ -0,0 +1,15 @@
+from .client import *
+from .dashboard import (
+ ClientDashboardView,
+ DashboardRouterView,
+ ManagerDashboardView,
+ VolunteerDashboardView,
+)
+
+from django.contrib.auth.views import LoginView
+from django.urls import reverse_lazy
+
+
+class MyLoginView(LoginView):
+ template_name = "afbcore/login.html"
+ success_url = reverse_lazy("afbcore:dashboard")
diff --git a/afb-vite/afbcore/views/client.py b/afb-vite/afbcore/views/client.py
new file mode 100644
index 00000000..fa8d61d4
--- /dev/null
+++ b/afb-vite/afbcore/views/client.py
@@ -0,0 +1,28 @@
+from django.shortcuts import render
+
+# Create your views here.
+# some_app/views.py
+from django.views.generic import TemplateView
+from django.views.generic.edit import CreateView
+from django.views.generic.edit import FormView
+
+from afbcore.forms import ClientSignupForm
+from afbcore.models import Client
+
+
+class AboutView(TemplateView):
+ template_name = "about.html"
+
+
+class DashboardView(TemplateView):
+ template_name = "dashboard/client.html"
+
+
+class ClientSignupFormView(FormView):
+ template_name = "afbcore/client_signup_form.html"
+ form_class = ClientSignupForm
+ success_url = "/dashboard"
+
+
+class ClientRequestView(TemplateView):
+ template_name = "afbcore/client_request.html"
diff --git a/afb-vite/afbcore/views/dashboard.py b/afb-vite/afbcore/views/dashboard.py
new file mode 100644
index 00000000..0ca18b71
--- /dev/null
+++ b/afb-vite/afbcore/views/dashboard.py
@@ -0,0 +1,42 @@
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.http import Http404
+from django.shortcuts import render
+from django.views.generic import TemplateView
+from django.views import View
+
+from afbcore.models import Client, Manager, Volunteer
+
+
+class DashboardRouterView(LoginRequiredMixin, View):
+ def get(self, request):
+ # Route to the specific dashboard based on user type
+ if isinstance(request.user, Client):
+ # Internal redirect to ClientDashboardView
+ return ClientDashboardView.as_view()(request)
+ elif isinstance(request.user, Manager):
+ # Internal redirect to ManagerDashboardView
+ return ManagerDashboardView.as_view()(request)
+ elif isinstance(request.user, Volunteer):
+ # Internal redirect to VolunteerDashboardView
+ return VolunteerDashboardView.as_view()(request)
+ else:
+ # 404
+ raise Http404("Page not found")
+
+
+class ClientDashboardView(LoginRequiredMixin, TemplateView):
+ def get(self, request):
+ # Add client-specific dashboard logic here
+ return render(request, "dashboard/client.html")
+
+
+class ManagerDashboardView(LoginRequiredMixin, TemplateView):
+ def get(self, request):
+ # Add manager-specific dashboard logic here
+ return render(request, "dashboard/manager.html")
+
+
+class VolunteerDashboardView(LoginRequiredMixin, TemplateView):
+ def get(self, request):
+ # Add volunteer-specific dashboard logic here
+ return render(request, "dashboard/volunteer.html")
diff --git a/afb-vite/afbcore/views/manager.py b/afb-vite/afbcore/views/manager.py
new file mode 100644
index 00000000..52fc867d
--- /dev/null
+++ b/afb-vite/afbcore/views/manager.py
@@ -0,0 +1,10 @@
+from django.shortcuts import render
+
+# Create your views here.
+# some_app/views.py
+from django.views.generic import TemplateView
+from django.views.generic.edit import CreateView
+from django.views.generic.edit import FormView
+
+from afbcore.forms import ManagerForm
+from afbcore.models import Manager
diff --git a/afb-vite/afbcore/views/volunteer.py b/afb-vite/afbcore/views/volunteer.py
new file mode 100644
index 00000000..abf23fd5
--- /dev/null
+++ b/afb-vite/afbcore/views/volunteer.py
@@ -0,0 +1,10 @@
+from django.shortcuts import render
+
+# Create your views here.
+# some_app/views.py
+from django.views.generic import TemplateView
+from django.views.generic.edit import CreateView
+from django.views.generic.edit import FormView
+
+from afbcore.forms import VolunteerForm
+from afbcore.models import Volunteer
diff --git a/afb-vite/manage.py b/afb-vite/manage.py
new file mode 100755
index 00000000..157be528
--- /dev/null
+++ b/afb-vite/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+ """Run administrative tasks."""
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "afb.settings")
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/afb-vite/requirements.in b/afb-vite/requirements.in
new file mode 100644
index 00000000..bef3228d
--- /dev/null
+++ b/afb-vite/requirements.in
@@ -0,0 +1,39 @@
+#
+# Requirements file for afb-requests. Modify this file to
+# include the packages you want to install. Then, run:
+#
+# pip-compile --output-file requirements.txt requirements.in
+#
+# This will generate a new requirements.txt file with the
+# latest versions of the packages listed here.
+#
+# You can also run:
+#
+# pip-compile --upgrade --output-file requirements.txt requirements.in
+#
+# to upgrade all packages to their latest versions.
+#
+# See: https://github.com/jazzband/pip-tools
+#
+
+Django==4.2.5
+django-tailwind[reload]
+django-unfold
+django-crispy-forms
+crispy-tailwind
+pillow
+
+django-vite
+
+phonenumbers
+django-phonenumber-field
+
+pip-tools
+pre-commit
+
+# Copilot suggestions
+# django-extensions
+# django-allauth
+# django-address
+# django-money
+# django-countries
diff --git a/afb-vite/requirements.txt b/afb-vite/requirements.txt
new file mode 100644
index 00000000..dbd7388f
--- /dev/null
+++ b/afb-vite/requirements.txt
@@ -0,0 +1,77 @@
+#
+# This file is autogenerated by pip-compile with Python 3.11
+# by the following command:
+#
+# pip-compile --output-file=requirements.txt requirements.in
+#
+asgiref==3.7.2
+ # via django
+build==1.0.3
+ # via pip-tools
+cfgv==3.4.0
+ # via pre-commit
+click==8.1.7
+ # via pip-tools
+crispy-tailwind==0.5.0
+ # via -r requirements.in
+distlib==0.3.7
+ # via virtualenv
+django==4.2.5
+ # via
+ # -r requirements.in
+ # django-browser-reload
+ # django-crispy-forms
+ # django-phonenumber-field
+ # django-tailwind
+ # django-unfold
+ # django-vite
+django-browser-reload==1.11.0
+ # via django-tailwind
+django-crispy-forms==2.0
+ # via
+ # -r requirements.in
+ # crispy-tailwind
+django-phonenumber-field==7.1.0
+ # via -r requirements.in
+django-tailwind[reload]==3.6.0
+ # via -r requirements.in
+django-unfold==0.10.0
+ # via -r requirements.in
+django-vite==2.1.3
+ # via -r requirements.in
+filelock==3.12.4
+ # via virtualenv
+identify==2.5.29
+ # via pre-commit
+importlib-metadata==6.7.0
+ # via django-unfold
+nodeenv==1.8.0
+ # via pre-commit
+packaging==23.1
+ # via build
+phonenumbers==8.13.22
+ # via -r requirements.in
+pillow==10.0.1
+ # via -r requirements.in
+pip-tools==7.3.0
+ # via -r requirements.in
+platformdirs==3.10.0
+ # via virtualenv
+pre-commit==3.4.0
+ # via -r requirements.in
+pyproject-hooks==1.0.0
+ # via build
+pyyaml==6.0.1
+ # via pre-commit
+sqlparse==0.4.4
+ # via django
+virtualenv==20.24.5
+ # via pre-commit
+wheel==0.41.2
+ # via pip-tools
+zipp==3.17.0
+ # via importlib-metadata
+
+# The following packages are considered to be unsafe in a requirements file:
+# pip
+# setuptools
diff --git a/afb-vite/static/img/afb_icon_black.png b/afb-vite/static/img/afb_icon_black.png
new file mode 100755
index 00000000..58570441
Binary files /dev/null and b/afb-vite/static/img/afb_icon_black.png differ
diff --git a/afb-vite/static/img/afb_icon_colour.png b/afb-vite/static/img/afb_icon_colour.png
new file mode 100755
index 00000000..e765e2ae
Binary files /dev/null and b/afb-vite/static/img/afb_icon_colour.png differ
diff --git a/afb-vite/static/img/afb_icon_white.png b/afb-vite/static/img/afb_icon_white.png
new file mode 100755
index 00000000..b73ea8aa
Binary files /dev/null and b/afb-vite/static/img/afb_icon_white.png differ
diff --git a/afb-vite/static/img/afb_logo_horizontal_black.png b/afb-vite/static/img/afb_logo_horizontal_black.png
new file mode 100755
index 00000000..4438123e
Binary files /dev/null and b/afb-vite/static/img/afb_logo_horizontal_black.png differ
diff --git a/afb-vite/static/img/afb_logo_horizontal_colour.png b/afb-vite/static/img/afb_logo_horizontal_colour.png
new file mode 100755
index 00000000..75762bd2
Binary files /dev/null and b/afb-vite/static/img/afb_logo_horizontal_colour.png differ
diff --git a/afb-vite/static/img/afb_logo_horizontal_white.png b/afb-vite/static/img/afb_logo_horizontal_white.png
new file mode 100755
index 00000000..4369718e
Binary files /dev/null and b/afb-vite/static/img/afb_logo_horizontal_white.png differ
diff --git a/afb-vite/static/img/afb_logo_vertical_black.png b/afb-vite/static/img/afb_logo_vertical_black.png
new file mode 100755
index 00000000..798eeb41
Binary files /dev/null and b/afb-vite/static/img/afb_logo_vertical_black.png differ
diff --git a/afb-vite/static/img/afb_logo_vertical_colour.png b/afb-vite/static/img/afb_logo_vertical_colour.png
new file mode 100755
index 00000000..28c2aae8
Binary files /dev/null and b/afb-vite/static/img/afb_logo_vertical_colour.png differ
diff --git a/afb-vite/static/img/afb_logo_vertical_white.png b/afb-vite/static/img/afb_logo_vertical_white.png
new file mode 100755
index 00000000..70244ea0
Binary files /dev/null and b/afb-vite/static/img/afb_logo_vertical_white.png differ
diff --git a/afb-vite/static/img/favicons/android-icon-144x144.png b/afb-vite/static/img/favicons/android-icon-144x144.png
new file mode 100644
index 00000000..7a2f70a4
Binary files /dev/null and b/afb-vite/static/img/favicons/android-icon-144x144.png differ
diff --git a/afb-vite/static/img/favicons/android-icon-192x192.png b/afb-vite/static/img/favicons/android-icon-192x192.png
new file mode 100644
index 00000000..d0ef1744
Binary files /dev/null and b/afb-vite/static/img/favicons/android-icon-192x192.png differ
diff --git a/afb-vite/static/img/favicons/android-icon-36x36.png b/afb-vite/static/img/favicons/android-icon-36x36.png
new file mode 100644
index 00000000..c4dcc530
Binary files /dev/null and b/afb-vite/static/img/favicons/android-icon-36x36.png differ
diff --git a/afb-vite/static/img/favicons/android-icon-48x48.png b/afb-vite/static/img/favicons/android-icon-48x48.png
new file mode 100644
index 00000000..b4d140c6
Binary files /dev/null and b/afb-vite/static/img/favicons/android-icon-48x48.png differ
diff --git a/afb-vite/static/img/favicons/android-icon-72x72.png b/afb-vite/static/img/favicons/android-icon-72x72.png
new file mode 100644
index 00000000..557f19d4
Binary files /dev/null and b/afb-vite/static/img/favicons/android-icon-72x72.png differ
diff --git a/afb-vite/static/img/favicons/android-icon-96x96.png b/afb-vite/static/img/favicons/android-icon-96x96.png
new file mode 100644
index 00000000..4fb75405
Binary files /dev/null and b/afb-vite/static/img/favicons/android-icon-96x96.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon-114x114.png b/afb-vite/static/img/favicons/apple-icon-114x114.png
new file mode 100644
index 00000000..5fd30056
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon-114x114.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon-120x120.png b/afb-vite/static/img/favicons/apple-icon-120x120.png
new file mode 100644
index 00000000..73341f3b
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon-120x120.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon-144x144.png b/afb-vite/static/img/favicons/apple-icon-144x144.png
new file mode 100644
index 00000000..7a2f70a4
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon-144x144.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon-152x152.png b/afb-vite/static/img/favicons/apple-icon-152x152.png
new file mode 100644
index 00000000..a47d08a3
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon-152x152.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon-180x180.png b/afb-vite/static/img/favicons/apple-icon-180x180.png
new file mode 100644
index 00000000..c30a725b
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon-180x180.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon-57x57.png b/afb-vite/static/img/favicons/apple-icon-57x57.png
new file mode 100644
index 00000000..9949de1c
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon-57x57.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon-60x60.png b/afb-vite/static/img/favicons/apple-icon-60x60.png
new file mode 100644
index 00000000..883282d4
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon-60x60.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon-72x72.png b/afb-vite/static/img/favicons/apple-icon-72x72.png
new file mode 100644
index 00000000..557f19d4
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon-72x72.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon-76x76.png b/afb-vite/static/img/favicons/apple-icon-76x76.png
new file mode 100644
index 00000000..bcad7b73
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon-76x76.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon-precomposed.png b/afb-vite/static/img/favicons/apple-icon-precomposed.png
new file mode 100644
index 00000000..f9193c96
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon-precomposed.png differ
diff --git a/afb-vite/static/img/favicons/apple-icon.png b/afb-vite/static/img/favicons/apple-icon.png
new file mode 100644
index 00000000..f9193c96
Binary files /dev/null and b/afb-vite/static/img/favicons/apple-icon.png differ
diff --git a/afb-vite/static/img/favicons/browserconfig.xml b/afb-vite/static/img/favicons/browserconfig.xml
new file mode 100644
index 00000000..7d453d3b
--- /dev/null
+++ b/afb-vite/static/img/favicons/browserconfig.xml
@@ -0,0 +1,2 @@
+
+#ffffff
diff --git a/afb-vite/static/img/favicons/favicon-16x16.png b/afb-vite/static/img/favicons/favicon-16x16.png
new file mode 100644
index 00000000..4360d5f9
Binary files /dev/null and b/afb-vite/static/img/favicons/favicon-16x16.png differ
diff --git a/afb-vite/static/img/favicons/favicon-32x32.png b/afb-vite/static/img/favicons/favicon-32x32.png
new file mode 100644
index 00000000..acb280a7
Binary files /dev/null and b/afb-vite/static/img/favicons/favicon-32x32.png differ
diff --git a/afb-vite/static/img/favicons/favicon-96x96.png b/afb-vite/static/img/favicons/favicon-96x96.png
new file mode 100644
index 00000000..4fb75405
Binary files /dev/null and b/afb-vite/static/img/favicons/favicon-96x96.png differ
diff --git a/afb-vite/static/img/favicons/favicon.ico b/afb-vite/static/img/favicons/favicon.ico
new file mode 100644
index 00000000..2dace648
Binary files /dev/null and b/afb-vite/static/img/favicons/favicon.ico differ
diff --git a/afb-vite/static/img/favicons/manifest.json b/afb-vite/static/img/favicons/manifest.json
new file mode 100644
index 00000000..758f8d2a
--- /dev/null
+++ b/afb-vite/static/img/favicons/manifest.json
@@ -0,0 +1,41 @@
+{
+ "name": "App",
+ "icons": [
+ {
+ "src": "\/android-icon-36x36.png",
+ "sizes": "36x36",
+ "type": "image\/png",
+ "density": "0.75"
+ },
+ {
+ "src": "\/android-icon-48x48.png",
+ "sizes": "48x48",
+ "type": "image\/png",
+ "density": "1.0"
+ },
+ {
+ "src": "\/android-icon-72x72.png",
+ "sizes": "72x72",
+ "type": "image\/png",
+ "density": "1.5"
+ },
+ {
+ "src": "\/android-icon-96x96.png",
+ "sizes": "96x96",
+ "type": "image\/png",
+ "density": "2.0"
+ },
+ {
+ "src": "\/android-icon-144x144.png",
+ "sizes": "144x144",
+ "type": "image\/png",
+ "density": "3.0"
+ },
+ {
+ "src": "\/android-icon-192x192.png",
+ "sizes": "192x192",
+ "type": "image\/png",
+ "density": "4.0"
+ }
+ ]
+}
diff --git a/afb-vite/static/img/favicons/ms-icon-144x144.png b/afb-vite/static/img/favicons/ms-icon-144x144.png
new file mode 100644
index 00000000..7a2f70a4
Binary files /dev/null and b/afb-vite/static/img/favicons/ms-icon-144x144.png differ
diff --git a/afb-vite/static/img/favicons/ms-icon-150x150.png b/afb-vite/static/img/favicons/ms-icon-150x150.png
new file mode 100644
index 00000000..7c3ed729
Binary files /dev/null and b/afb-vite/static/img/favicons/ms-icon-150x150.png differ
diff --git a/afb-vite/static/img/favicons/ms-icon-310x310.png b/afb-vite/static/img/favicons/ms-icon-310x310.png
new file mode 100644
index 00000000..55e1907a
Binary files /dev/null and b/afb-vite/static/img/favicons/ms-icon-310x310.png differ
diff --git a/afb-vite/static/img/favicons/ms-icon-70x70.png b/afb-vite/static/img/favicons/ms-icon-70x70.png
new file mode 100644
index 00000000..d9c85a51
Binary files /dev/null and b/afb-vite/static/img/favicons/ms-icon-70x70.png differ
diff --git a/afb-vite/ui/.gitignore b/afb-vite/ui/.gitignore
new file mode 100644
index 00000000..0125458e
--- /dev/null
+++ b/afb-vite/ui/.gitignore
@@ -0,0 +1,118 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+.env.production
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
diff --git a/afb-vite/ui/.prettierrc.json b/afb-vite/ui/.prettierrc.json
new file mode 100644
index 00000000..0967ef42
--- /dev/null
+++ b/afb-vite/ui/.prettierrc.json
@@ -0,0 +1 @@
+{}
diff --git a/afb-vite/ui/README.md b/afb-vite/ui/README.md
new file mode 100644
index 00000000..b2195f56
--- /dev/null
+++ b/afb-vite/ui/README.md
@@ -0,0 +1,31 @@
+# ui2
+
+https://vitejs.dev/guide/cli.html
+
+- **template of:** vite + vue + typescript
+- **tailwindcss:** v3.x
+
+## Started
+```bash
+yarn
+# or `npm install`
+```
+
+---
+## Develop
+```bash
+yarn dev
+# or `npm run dev`
+```
+
+---
+## Build
+```bash
+yarn build
+# or `npm run build`
+```
+
+---
+
+
+
diff --git a/afb-vite/ui/index.html b/afb-vite/ui/index.html
new file mode 100644
index 00000000..11603f87
--- /dev/null
+++ b/afb-vite/ui/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite App
+
+
+
+
+
+
diff --git a/afb-vite/ui/package.json b/afb-vite/ui/package.json
new file mode 100644
index 00000000..30a28de4
--- /dev/null
+++ b/afb-vite/ui/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "ui",
+ "version": "0.1.0",
+ "scripts": {
+ "dev": "vite",
+ "TODO": "postcss e.g. postcss styles.css -o src/styles.css",
+ "build": "vue-tsc --noEmit && vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@headlessui/vue": "^1.7.16",
+ "@heroicons/vue": "^2.0.18",
+ "@tailwindcss/aspect-ratio": "^0.4.2",
+ "@tailwindcss/forms": "^0.5.6",
+ "vue": "^3.2.25"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^2.0.0",
+ "autoprefixer": "^10.4.16",
+ "postcss": "^8.4.31",
+ "postcss-import": "^15.1.0",
+ "prettier": "^2.5.1",
+ "prettier-plugin-tailwindcss": "^0.1.5",
+ "tailwindcss": "^3.3.5",
+ "typescript": "^4.4.4",
+ "vitawind": "^2.0.0",
+ "vite": "^2.7.2",
+ "vue-tsc": "^0.29.8"
+ }
+}
diff --git a/afb-vite/ui/postcss.config.js b/afb-vite/ui/postcss.config.js
new file mode 100644
index 00000000..aff08f62
--- /dev/null
+++ b/afb-vite/ui/postcss.config.js
@@ -0,0 +1,12 @@
+module.exports = {
+ // plugins: {
+ // 'postcss-import': {},
+ // tailwindcss: {},
+ // autoprefixer: {},
+ // },
+ plugins: [
+ require('postcss-import'),
+ require('tailwindcss'),
+ require('autoprefixer'),
+ ]
+}
diff --git a/afb-vite/ui/powered-by-vitawind-bright.png b/afb-vite/ui/powered-by-vitawind-bright.png
new file mode 100644
index 00000000..5da40b0d
Binary files /dev/null and b/afb-vite/ui/powered-by-vitawind-bright.png differ
diff --git a/afb-vite/ui/public/favicon.ico b/afb-vite/ui/public/favicon.ico
new file mode 100644
index 00000000..df36fcfb
Binary files /dev/null and b/afb-vite/ui/public/favicon.ico differ
diff --git a/afb-vite/ui/src/App.vue b/afb-vite/ui/src/App.vue
new file mode 100644
index 00000000..2a96fd2a
--- /dev/null
+++ b/afb-vite/ui/src/App.vue
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open main menu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
{{ user.name }}
+
{{ user.email }}
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/afb-vite/ui/src/assets/logo.png b/afb-vite/ui/src/assets/logo.png
new file mode 100644
index 00000000..f3d2503f
Binary files /dev/null and b/afb-vite/ui/src/assets/logo.png differ
diff --git a/afb-vite/ui/src/assets/powered-by-vitawind-bright.png b/afb-vite/ui/src/assets/powered-by-vitawind-bright.png
new file mode 100644
index 00000000..5da40b0d
Binary files /dev/null and b/afb-vite/ui/src/assets/powered-by-vitawind-bright.png differ
diff --git a/afb-vite/ui/src/components/DropdownNav.vue b/afb-vite/ui/src/components/DropdownNav.vue
new file mode 100644
index 00000000..3d4d18de
--- /dev/null
+++ b/afb-vite/ui/src/components/DropdownNav.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
diff --git a/afb-vite/ui/src/components/HelloWorld.vue b/afb-vite/ui/src/components/HelloWorld.vue
new file mode 100644
index 00000000..5b71b39d
--- /dev/null
+++ b/afb-vite/ui/src/components/HelloWorld.vue
@@ -0,0 +1,64 @@
+
+
+
+
+ {{ msg }}
+
+
+
+ Recommended IDE setup:
+ VSCode
+ +
+ Volar
+
+
+
+
+ Vite Documentation
+
+ |
+ Vue 3 Documentation
+
+
+
+
+ Edit
+ components/HelloWorld.vue
to test hot
+ module replacement.
+
+
+
+
diff --git a/afb-vite/ui/src/env.d.ts b/afb-vite/ui/src/env.d.ts
new file mode 100644
index 00000000..d27eb5a3
--- /dev/null
+++ b/afb-vite/ui/src/env.d.ts
@@ -0,0 +1,8 @@
+///
+
+declare module '*.vue' {
+ import { DefineComponent } from 'vue'
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
diff --git a/afb-vite/ui/src/index.css b/afb-vite/ui/src/index.css
new file mode 100644
index 00000000..2436ee6c
--- /dev/null
+++ b/afb-vite/ui/src/index.css
@@ -0,0 +1,27 @@
+
+/**
+ * This injects Tailwind's base styles and any base styles registered by
+ * plugins.
+ */
+@tailwind base;
+
+/**
+ * This injects Tailwind's component classes and any component classes
+ * registered by plugins.
+ */
+@tailwind components;
+
+/**
+ * This injects Tailwind's utility classes and any utility classes registered
+ * by plugins.
+ */
+@tailwind utilities;
+
+/**
+ * Use this directive to control where Tailwind injects the hover, focus,
+ * responsive, dark mode, and other variants of each class.
+ *
+ * If omitted, Tailwind will append these classes to the very end of
+ * your stylesheet by default.
+ */
+@tailwind variants;
diff --git a/afb-vite/ui/src/main.ts b/afb-vite/ui/src/main.ts
new file mode 100644
index 00000000..97a04294
--- /dev/null
+++ b/afb-vite/ui/src/main.ts
@@ -0,0 +1,8 @@
+// add the beginning of your app entry
+import 'vite/modulepreload-polyfill'
+
+import { createApp } from 'vue'
+import App from './App.vue'
+import './index.css'
+
+createApp(App).mount('#app')
diff --git a/afb-vite/ui/tailwind.config.js b/afb-vite/ui/tailwind.config.js
new file mode 100644
index 00000000..e86da557
--- /dev/null
+++ b/afb-vite/ui/tailwind.config.js
@@ -0,0 +1,18 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ "./index.html",
+ "./src/**/*.{vue,html,js,ts,jsx,tsx}",
+ "./src/views/*.{vue,html,js,ts,jsx,tsx}",
+ "./src/components/*.{vue,html,js,ts,jsx,tsx}",
+ "../afbcore/templates/**/*.html",
+ "../afbcore/templates/*.html"
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [
+ require('@tailwindcss/forms'),
+ require('@tailwindcss/aspect-ratio')
+ ],
+}
diff --git a/afb-vite/ui/tsconfig.json b/afb-vite/ui/tsconfig.json
new file mode 100644
index 00000000..8617c8a5
--- /dev/null
+++ b/afb-vite/ui/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "useDefineForClassFields": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "strict": true,
+ "jsx": "preserve",
+ "sourceMap": true,
+ "resolveJsonModule": true,
+ "esModuleInterop": true,
+ "lib": ["esnext", "dom"]
+ },
+ "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
+}
diff --git a/afb-vite/ui/vite.config.ts b/afb-vite/ui/vite.config.ts
new file mode 100644
index 00000000..2e9d7bc1
--- /dev/null
+++ b/afb-vite/ui/vite.config.ts
@@ -0,0 +1,41 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ base: '/static/',
+ server: {
+ host: 'localhost',
+ port: 3000,
+ open: false,
+ watch: {
+ usePolling: false,
+ disableGlobbing: false,
+ },
+ },
+ plugins: [vue()],
+ // https://github.com/MrBin99/django-vite#vitejs
+ // https://vitejs.dev/guide/backend-integration.html
+ build: {
+ outDir: 'dist/',
+ emptyOutDir: true,
+
+ // https://stackoverflow.com/questions/74177078/styles-is-missing-after-i-bundle-my-project-with-vite
+ // https://vitejs.dev/config/build-options.html#build-csscodesplit
+ // https://github.com/vitejs/vite/issues/10630
+ cssCodeSplit: true,
+
+ manifest: true,
+ // As this is in SSR and not in SPA, you don't have an index.html that
+ // ViteJS can use to determine which files to compile. You need to
+ // tell it directly.
+ rollupOptions: {
+ input: 'src/main.ts',
+ // See: https://ilikerobots.medium.com/django-vue-vite-rest-not-required-ca63cfa558fd
+ // output: {
+ // dir: '..//static/vue/',
+ // entryFileNames: '[name].js',
+ // }
+ }
+ }
+})
diff --git a/afb-vite/ui/yarn.lock b/afb-vite/ui/yarn.lock
new file mode 100644
index 00000000..4b6a2bde
--- /dev/null
+++ b/afb-vite/ui/yarn.lock
@@ -0,0 +1,1565 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@alloc/quick-lru@^5.2.0":
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz"
+ integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
+
+"@babel/helper-string-parser@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz"
+ integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
+
+"@babel/helper-validator-identifier@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz"
+ integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
+"@babel/parser@^7.23.0", "@babel/parser@^7.6.0", "@babel/parser@^7.9.6":
+ version "7.23.0"
+ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz"
+ integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
+
+"@babel/types@^7.6.1", "@babel/types@^7.9.6":
+ version "7.23.0"
+ resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz"
+ integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
+ dependencies:
+ "@babel/helper-string-parser" "^7.22.5"
+ "@babel/helper-validator-identifier" "^7.22.20"
+ to-fast-properties "^2.0.0"
+
+"@emmetio/abbreviation@^2.3.3":
+ version "2.3.3"
+ resolved "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz"
+ integrity sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==
+ dependencies:
+ "@emmetio/scanner" "^1.0.4"
+
+"@emmetio/css-abbreviation@^2.1.8":
+ version "2.1.8"
+ resolved "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz"
+ integrity sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==
+ dependencies:
+ "@emmetio/scanner" "^1.0.4"
+
+"@emmetio/scanner@^1.0.4":
+ version "1.0.4"
+ resolved "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.4.tgz"
+ integrity sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==
+
+"@esbuild/linux-loong64@0.14.54":
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
+ integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==
+
+"@headlessui/vue@^1.7.16":
+ version "1.7.16"
+ resolved "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.16.tgz"
+ integrity sha512-nKT+nf/q6x198SsyK54mSszaQl/z+QxtASmgMEJtpxSX2Q0OPJX0upS/9daDyiECpeAsvjkoOrm2O/6PyBQ+Qg==
+
+"@heroicons/vue@^2.0.18":
+ version "2.0.18"
+ resolved "https://registry.npmjs.org/@heroicons/vue/-/vue-2.0.18.tgz"
+ integrity sha512-BcTC9nq2TkwNSfQuqo96J7ehx4etezypc2YeTq7KsXWxrcrerhkgjLrxGRBnStN0wrXo0Gv4BInybqz5uBG6Cw==
+
+"@jridgewell/gen-mapping@^0.3.2":
+ version "0.3.3"
+ resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz"
+ integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
+ dependencies:
+ "@jridgewell/set-array" "^1.0.1"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.1"
+ resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz"
+ integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
+
+"@jridgewell/set-array@^1.0.1":
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz"
+ integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
+
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15":
+ version "1.4.15"
+ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"
+ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@jridgewell/trace-mapping@^0.3.9":
+ version "0.3.20"
+ resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz"
+ integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+ version "1.2.8"
+ resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@tailwindcss/aspect-ratio@^0.4.2":
+ version "0.4.2"
+ resolved "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz"
+ integrity sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==
+
+"@tailwindcss/forms@^0.5.6":
+ version "0.5.6"
+ resolved "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.6.tgz"
+ integrity sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==
+ dependencies:
+ mini-svg-data-uri "^1.2.3"
+
+"@vitejs/plugin-vue@^2.0.0":
+ version "2.3.4"
+ resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.4.tgz"
+ integrity sha512-IfFNbtkbIm36O9KB8QodlwwYvTEsJb4Lll4c2IwB3VHc2gie2mSPtSzL0eYay7X2jd/2WX02FjSGTWR6OPr/zg==
+
+"@volar/code-gen@0.29.8":
+ version "0.29.8"
+ resolved "https://registry.npmjs.org/@volar/code-gen/-/code-gen-0.29.8.tgz"
+ integrity sha512-eohLLUqPChHRPDFT5gXn4V6pr/CeTri7Ou5GI26lUvBRRAbP8p+oYfQRcbMPGeKmVkYjfVj0chsxQGx6T8PQ4Q==
+ dependencies:
+ "@volar/shared" "0.29.8"
+ "@volar/source-map" "0.29.8"
+
+"@volar/html2pug@0.29.8":
+ version "0.29.8"
+ resolved "https://registry.npmjs.org/@volar/html2pug/-/html2pug-0.29.8.tgz"
+ integrity sha512-bhSNXg8A2aD3w0B+CwmHjqCAaKtj5rORbE5C/q/UdGqptJbC6STCmi30KuRTdfPhR++Xb18Hauf3s/WCmtNAPA==
+ dependencies:
+ domelementtype "^2.2.0"
+ domhandler "^4.2.2"
+ htmlparser2 "^7.1.2"
+ pug "^3.0.2"
+
+"@volar/shared@0.29.8":
+ version "0.29.8"
+ resolved "https://registry.npmjs.org/@volar/shared/-/shared-0.29.8.tgz"
+ integrity sha512-Y1NN6irkIukD+T0wf4p/dHWYL90sacN2e2lYoDXxRlvoYxwANnHgw0J0Rcp+yw58ElWRScdG7/YntEIuZWeJsw==
+ dependencies:
+ upath "^2.0.1"
+ vscode-jsonrpc "^8.0.0-next.2"
+ vscode-uri "^3.0.2"
+
+"@volar/source-map@0.29.8":
+ version "0.29.8"
+ resolved "https://registry.npmjs.org/@volar/source-map/-/source-map-0.29.8.tgz"
+ integrity sha512-7w+UoYtnc6UQu30CgMVvx0YN4dzDgP4TIsSmUaW62AGmxU9Lxwp3Kkn/4N8efi91z8ma5Z78v/HddyJPwAC3LA==
+ dependencies:
+ "@volar/shared" "0.29.8"
+
+"@volar/transforms@0.29.8":
+ version "0.29.8"
+ resolved "https://registry.npmjs.org/@volar/transforms/-/transforms-0.29.8.tgz"
+ integrity sha512-o2hRa8CoDwYTO1Mu5KA47+1elUnYUjDaVhCvbyKlRfd8qpHea2llotArq7B6OORSL2M9DVs1IRJ5NGURBFeZ3Q==
+ dependencies:
+ "@volar/shared" "0.29.8"
+ vscode-languageserver "^8.0.0-next.2"
+
+"@volar/vue-code-gen@0.29.8":
+ version "0.29.8"
+ resolved "https://registry.npmjs.org/@volar/vue-code-gen/-/vue-code-gen-0.29.8.tgz"
+ integrity sha512-E1e7P2oktNC/DzgDBditfla4s8+HlUlluZ+BtcLvEdbkl3QEjujkB0x1wxguWzXmpWgLIDPtrS3Jzll5cCOkTg==
+ dependencies:
+ "@volar/code-gen" "0.29.8"
+ "@volar/shared" "0.29.8"
+ "@volar/source-map" "0.29.8"
+ "@vue/compiler-core" "^3.2.21"
+ "@vue/compiler-dom" "^3.2.21"
+ "@vue/shared" "^3.2.21"
+ upath "^2.0.1"
+
+"@vscode/emmet-helper@^2.8.0":
+ version "2.9.2"
+ resolved "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.9.2.tgz"
+ integrity sha512-MaGuyW+fa13q3aYsluKqclmh62Hgp0BpKIqS66fCxfOaBcVQ1OnMQxRRgQUYnCkxFISAQlkJ0qWWPyXjro1Qrg==
+ dependencies:
+ emmet "^2.4.3"
+ jsonc-parser "^2.3.0"
+ vscode-languageserver-textdocument "^1.0.1"
+ vscode-languageserver-types "^3.15.1"
+ vscode-uri "^2.1.2"
+
+"@vue/compiler-core@3.3.7", "@vue/compiler-core@^3.2.21":
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.7.tgz"
+ integrity sha512-pACdY6YnTNVLXsB86YD8OF9ihwpolzhhtdLVHhBL6do/ykr6kKXNYABRtNMGrsQXpEXXyAdwvWWkuTbs4MFtPQ==
+ dependencies:
+ "@babel/parser" "^7.23.0"
+ "@vue/shared" "3.3.7"
+ estree-walker "^2.0.2"
+ source-map-js "^1.0.2"
+
+"@vue/compiler-dom@3.3.7", "@vue/compiler-dom@^3.2.21":
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.7.tgz"
+ integrity sha512-0LwkyJjnUPssXv/d1vNJ0PKfBlDoQs7n81CbO6Q0zdL7H1EzqYRrTVXDqdBVqro0aJjo/FOa1qBAPVI4PGSHBw==
+ dependencies:
+ "@vue/compiler-core" "3.3.7"
+ "@vue/shared" "3.3.7"
+
+"@vue/compiler-sfc@3.3.7":
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.7.tgz"
+ integrity sha512-7pfldWy/J75U/ZyYIXRVqvLRw3vmfxDo2YLMwVtWVNew8Sm8d6wodM+OYFq4ll/UxfqVr0XKiVwti32PCrruAw==
+ dependencies:
+ "@babel/parser" "^7.23.0"
+ "@vue/compiler-core" "3.3.7"
+ "@vue/compiler-dom" "3.3.7"
+ "@vue/compiler-ssr" "3.3.7"
+ "@vue/reactivity-transform" "3.3.7"
+ "@vue/shared" "3.3.7"
+ estree-walker "^2.0.2"
+ magic-string "^0.30.5"
+ postcss "^8.4.31"
+ source-map-js "^1.0.2"
+
+"@vue/compiler-ssr@3.3.7":
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.7.tgz"
+ integrity sha512-TxOfNVVeH3zgBc82kcUv+emNHo+vKnlRrkv8YvQU5+Y5LJGJwSNzcmLUoxD/dNzv0bhQ/F0s+InlgV0NrApJZg==
+ dependencies:
+ "@vue/compiler-dom" "3.3.7"
+ "@vue/shared" "3.3.7"
+
+"@vue/reactivity-transform@3.3.7":
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.7.tgz"
+ integrity sha512-APhRmLVbgE1VPGtoLQoWBJEaQk4V8JUsqrQihImVqKT+8U6Qi3t5ATcg4Y9wGAPb3kIhetpufyZ1RhwbZCIdDA==
+ dependencies:
+ "@babel/parser" "^7.23.0"
+ "@vue/compiler-core" "3.3.7"
+ "@vue/shared" "3.3.7"
+ estree-walker "^2.0.2"
+ magic-string "^0.30.5"
+
+"@vue/reactivity@3.3.7", "@vue/reactivity@^3.2.21":
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.7.tgz"
+ integrity sha512-cZNVjWiw00708WqT0zRpyAgduG79dScKEPYJXq2xj/aMtk3SKvL3FBt2QKUlh6EHBJ1m8RhBY+ikBUzwc7/khg==
+ dependencies:
+ "@vue/shared" "3.3.7"
+
+"@vue/runtime-core@3.3.7":
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.7.tgz"
+ integrity sha512-LHq9du3ubLZFdK/BP0Ysy3zhHqRfBn80Uc+T5Hz3maFJBGhci1MafccnL3rpd5/3wVfRHAe6c+PnlO2PAavPTQ==
+ dependencies:
+ "@vue/reactivity" "3.3.7"
+ "@vue/shared" "3.3.7"
+
+"@vue/runtime-dom@3.3.7":
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.7.tgz"
+ integrity sha512-PFQU1oeJxikdDmrfoNQay5nD4tcPNYixUBruZzVX/l0eyZvFKElZUjW4KctCcs52nnpMGO6UDK+jF5oV4GT5Lw==
+ dependencies:
+ "@vue/runtime-core" "3.3.7"
+ "@vue/shared" "3.3.7"
+ csstype "^3.1.2"
+
+"@vue/server-renderer@3.3.7":
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.7.tgz"
+ integrity sha512-UlpKDInd1hIZiNuVVVvLgxpfnSouxKQOSE2bOfQpBuGwxRV/JqqTCyyjXUWiwtVMyeRaZhOYYqntxElk8FhBhw==
+ dependencies:
+ "@vue/compiler-ssr" "3.3.7"
+ "@vue/shared" "3.3.7"
+
+"@vue/shared@3.3.7", "@vue/shared@^3.2.21":
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.3.7.tgz"
+ integrity sha512-N/tbkINRUDExgcPTBvxNkvHGu504k8lzlNQRITVnm6YjOjwa4r0nnbd4Jb01sNpur5hAllyRJzSK5PvB9PPwRg==
+
+acorn@^7.1.1:
+ version "7.4.1"
+ resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
+ integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
+
+any-promise@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz"
+ integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
+
+anymatch@~3.1.2:
+ version "3.1.3"
+ resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
+arg@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz"
+ integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
+
+asap@~2.0.3:
+ version "2.0.6"
+ resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz"
+ integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
+
+assert-never@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz"
+ integrity sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==
+
+autoprefixer@^10.4.16, autoprefixer@^10.4.2:
+ version "10.4.16"
+ resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz"
+ integrity sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==
+ dependencies:
+ browserslist "^4.21.10"
+ caniuse-lite "^1.0.30001538"
+ fraction.js "^4.3.6"
+ normalize-range "^0.1.2"
+ picocolors "^1.0.0"
+ postcss-value-parser "^4.2.0"
+
+babel-walk@3.0.0-canary-5:
+ version "3.0.0-canary-5"
+ resolved "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz"
+ integrity sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==
+ dependencies:
+ "@babel/types" "^7.9.6"
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+binary-extensions@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
+ integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@^3.0.2, braces@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ dependencies:
+ fill-range "^7.0.1"
+
+browserslist@^4.21.10:
+ version "4.22.1"
+ resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz"
+ integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==
+ dependencies:
+ caniuse-lite "^1.0.30001541"
+ electron-to-chromium "^1.4.535"
+ node-releases "^2.0.13"
+ update-browserslist-db "^1.0.13"
+
+call-bind@^1.0.2:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz"
+ integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==
+ dependencies:
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.1"
+ set-function-length "^1.1.1"
+
+camelcase-css@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz"
+ integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
+
+caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541:
+ version "1.0.30001559"
+ resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001559.tgz"
+ integrity sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA==
+
+character-parser@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz"
+ integrity sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==
+ dependencies:
+ is-regex "^1.0.3"
+
+chokidar@^3.5.3:
+ version "3.5.3"
+ resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
+ integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+commander@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz"
+ integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+constantinople@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz"
+ integrity sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==
+ dependencies:
+ "@babel/parser" "^7.6.0"
+ "@babel/types" "^7.6.1"
+
+cssesc@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz"
+ integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
+csstype@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz"
+ integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
+
+define-data-property@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz"
+ integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==
+ dependencies:
+ get-intrinsic "^1.2.1"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.0"
+
+didyoumean@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz"
+ integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
+
+dlv@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz"
+ integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
+
+doctypes@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz"
+ integrity sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==
+
+dom-serializer@^1.0.1:
+ version "1.4.1"
+ resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz"
+ integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.2.0"
+ entities "^2.0.0"
+
+domelementtype@^2.0.1, domelementtype@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz"
+ integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
+
+domhandler@^4.2.0, domhandler@^4.2.2:
+ version "4.3.1"
+ resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz"
+ integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
+ dependencies:
+ domelementtype "^2.2.0"
+
+domutils@^2.8.0:
+ version "2.8.0"
+ resolved "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz"
+ integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
+ dependencies:
+ dom-serializer "^1.0.1"
+ domelementtype "^2.2.0"
+ domhandler "^4.2.0"
+
+electron-to-chromium@^1.4.535:
+ version "1.4.571"
+ resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.571.tgz"
+ integrity sha512-Sc+VtKwKCDj3f/kLBjdyjMpNzoZsU6WuL/wFb6EH8USmHEcebxRXcRrVpOpayxd52tuey4RUDpUsw5OS5LhJqg==
+
+emmet@^2.4.3:
+ version "2.4.6"
+ resolved "https://registry.npmjs.org/emmet/-/emmet-2.4.6.tgz"
+ integrity sha512-dJfbdY/hfeTyf/Ef7Y7ubLYzkBvPQ912wPaeVYpAxvFxkEBf/+hJu4H6vhAvFN6HlxqedlfVn2x1S44FfQ97pg==
+ dependencies:
+ "@emmetio/abbreviation" "^2.3.3"
+ "@emmetio/css-abbreviation" "^2.1.8"
+
+entities@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz"
+ integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+
+entities@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz"
+ integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
+
+esbuild-android-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
+ integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
+
+esbuild-android-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
+ integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
+
+esbuild-darwin-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
+ integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
+
+esbuild-darwin-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz"
+ integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
+
+esbuild-freebsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
+ integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
+
+esbuild-freebsd-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
+ integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
+
+esbuild-linux-32@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
+ integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
+
+esbuild-linux-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652"
+ integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
+
+esbuild-linux-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
+ integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
+
+esbuild-linux-arm@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
+ integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
+
+esbuild-linux-mips64le@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
+ integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
+
+esbuild-linux-ppc64le@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
+ integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
+
+esbuild-linux-riscv64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
+ integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
+
+esbuild-linux-s390x@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
+ integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
+
+esbuild-netbsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
+ integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
+
+esbuild-openbsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
+ integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
+
+esbuild-sunos-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
+ integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
+
+esbuild-windows-32@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
+ integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==
+
+esbuild-windows-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4"
+ integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
+
+esbuild-windows-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982"
+ integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==
+
+esbuild@^0.14.27:
+ version "0.14.54"
+ resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz"
+ integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==
+ optionalDependencies:
+ "@esbuild/linux-loong64" "0.14.54"
+ esbuild-android-64 "0.14.54"
+ esbuild-android-arm64 "0.14.54"
+ esbuild-darwin-64 "0.14.54"
+ esbuild-darwin-arm64 "0.14.54"
+ esbuild-freebsd-64 "0.14.54"
+ esbuild-freebsd-arm64 "0.14.54"
+ esbuild-linux-32 "0.14.54"
+ esbuild-linux-64 "0.14.54"
+ esbuild-linux-arm "0.14.54"
+ esbuild-linux-arm64 "0.14.54"
+ esbuild-linux-mips64le "0.14.54"
+ esbuild-linux-ppc64le "0.14.54"
+ esbuild-linux-riscv64 "0.14.54"
+ esbuild-linux-s390x "0.14.54"
+ esbuild-netbsd-64 "0.14.54"
+ esbuild-openbsd-64 "0.14.54"
+ esbuild-sunos-64 "0.14.54"
+ esbuild-windows-32 "0.14.54"
+ esbuild-windows-64 "0.14.54"
+ esbuild-windows-arm64 "0.14.54"
+
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+estree-walker@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz"
+ integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+
+fast-glob@^3.3.0:
+ version "3.3.1"
+ resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz"
+ integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
+fastq@^1.6.0:
+ version "1.15.0"
+ resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz"
+ integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
+ dependencies:
+ reusify "^1.0.4"
+
+fill-range@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+fraction.js@^4.3.6:
+ version "4.3.7"
+ resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz"
+ integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+fsevents@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz"
+ integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==
+ dependencies:
+ function-bind "^1.1.2"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ hasown "^2.0.0"
+
+glob-parent@^5.1.2, glob-parent@~5.1.2:
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+glob-parent@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz"
+ integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
+ dependencies:
+ is-glob "^4.0.3"
+
+glob@7.1.6:
+ version "7.1.6"
+ resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz"
+ integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+gopd@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz"
+ integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+ dependencies:
+ get-intrinsic "^1.1.3"
+
+has-property-descriptors@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz"
+ integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==
+ dependencies:
+ get-intrinsic "^1.2.2"
+
+has-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz"
+ integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
+
+has-symbols@^1.0.2, has-symbols@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz"
+ integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+has-tostringtag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz"
+ integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
+ dependencies:
+ has-symbols "^1.0.2"
+
+hasown@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz"
+ integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==
+ dependencies:
+ function-bind "^1.1.2"
+
+htmlparser2@^7.1.2:
+ version "7.2.0"
+ resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz"
+ integrity sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.2.2"
+ domutils "^2.8.0"
+ entities "^3.0.1"
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2:
+ version "2.0.4"
+ resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
+is-core-module@^2.13.0:
+ version "2.13.1"
+ resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz"
+ integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
+ dependencies:
+ hasown "^2.0.0"
+
+is-expression@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz"
+ integrity sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==
+ dependencies:
+ acorn "^7.1.1"
+ object-assign "^4.1.1"
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+ version "4.0.3"
+ resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-promise@^2.0.0:
+ version "2.2.2"
+ resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz"
+ integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
+
+is-regex@^1.0.3:
+ version "1.1.4"
+ resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz"
+ integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
+jiti@^1.19.1:
+ version "1.21.0"
+ resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz"
+ integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
+
+js-stringify@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz"
+ integrity sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==
+
+jsonc-parser@^2.3.0:
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz"
+ integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==
+
+jsonc-parser@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz"
+ integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
+
+jstransformer@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz"
+ integrity sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==
+ dependencies:
+ is-promise "^2.0.0"
+ promise "^7.0.1"
+
+lilconfig@^2.0.5, lilconfig@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz"
+ integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
+
+lines-and-columns@^1.1.6:
+ version "1.2.4"
+ resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz"
+ integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
+
+magic-string@^0.30.5:
+ version "0.30.5"
+ resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz"
+ integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==
+ dependencies:
+ "@jridgewell/sourcemap-codec" "^1.4.15"
+
+merge2@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromatch@^4.0.4, micromatch@^4.0.5:
+ version "4.0.5"
+ resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"
+ integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+ dependencies:
+ braces "^3.0.2"
+ picomatch "^2.3.1"
+
+mini-svg-data-uri@^1.2.3:
+ version "1.4.4"
+ resolved "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz"
+ integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==
+
+minimatch@^3.0.4:
+ version "3.1.2"
+ resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+mz@^2.7.0:
+ version "2.7.0"
+ resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz"
+ integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+ dependencies:
+ any-promise "^1.0.0"
+ object-assign "^4.0.1"
+ thenify-all "^1.0.0"
+
+nanoid@^3.3.6:
+ version "3.3.6"
+ resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz"
+ integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
+
+node-releases@^2.0.13:
+ version "2.0.13"
+ resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz"
+ integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+normalize-range@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz"
+ integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
+
+object-assign@^4.0.1, object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
+object-hash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz"
+ integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
+
+once@^1.3.0:
+ version "1.4.0"
+ resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+ dependencies:
+ wrappy "1"
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
+ integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+picocolors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
+ integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pify@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz"
+ integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
+
+pirates@^4.0.1:
+ version "4.0.6"
+ resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz"
+ integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==
+
+postcss-import@^15.1.0:
+ version "15.1.0"
+ resolved "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz"
+ integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==
+ dependencies:
+ postcss-value-parser "^4.0.0"
+ read-cache "^1.0.0"
+ resolve "^1.1.7"
+
+postcss-js@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz"
+ integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
+ dependencies:
+ camelcase-css "^2.0.1"
+
+postcss-load-config@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz"
+ integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==
+ dependencies:
+ lilconfig "^2.0.5"
+ yaml "^2.1.1"
+
+postcss-nested@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz"
+ integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==
+ dependencies:
+ postcss-selector-parser "^6.0.11"
+
+postcss-selector-parser@^6.0.11:
+ version "6.0.13"
+ resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz"
+ integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==
+ dependencies:
+ cssesc "^3.0.0"
+ util-deprecate "^1.0.2"
+
+postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
+ integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+
+postcss@^8.4.13, postcss@^8.4.23, postcss@^8.4.31, postcss@^8.4.8:
+ version "8.4.31"
+ resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz"
+ integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
+ dependencies:
+ nanoid "^3.3.6"
+ picocolors "^1.0.0"
+ source-map-js "^1.0.2"
+
+prettier-plugin-tailwindcss@^0.1.5:
+ version "0.1.13"
+ resolved "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.1.13.tgz"
+ integrity sha512-/EKQURUrxLu66CMUg4+1LwGdxnz8of7IDvrSLqEtDqhLH61SAlNNUSr90UTvZaemujgl3OH/VHg+fyGltrNixw==
+
+prettier@^2.5.1:
+ version "2.8.8"
+ resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz"
+ integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
+
+promise@^7.0.1:
+ version "7.3.1"
+ resolved "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz"
+ integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
+ dependencies:
+ asap "~2.0.3"
+
+pug-attrs@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz"
+ integrity sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==
+ dependencies:
+ constantinople "^4.0.1"
+ js-stringify "^1.0.2"
+ pug-runtime "^3.0.0"
+
+pug-code-gen@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz"
+ integrity sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==
+ dependencies:
+ constantinople "^4.0.1"
+ doctypes "^1.1.0"
+ js-stringify "^1.0.2"
+ pug-attrs "^3.0.0"
+ pug-error "^2.0.0"
+ pug-runtime "^3.0.0"
+ void-elements "^3.1.0"
+ with "^7.0.0"
+
+pug-error@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz"
+ integrity sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==
+
+pug-filters@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz"
+ integrity sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==
+ dependencies:
+ constantinople "^4.0.1"
+ jstransformer "1.0.0"
+ pug-error "^2.0.0"
+ pug-walk "^2.0.0"
+ resolve "^1.15.1"
+
+pug-lexer@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz"
+ integrity sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==
+ dependencies:
+ character-parser "^2.2.0"
+ is-expression "^4.0.0"
+ pug-error "^2.0.0"
+
+pug-linker@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz"
+ integrity sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==
+ dependencies:
+ pug-error "^2.0.0"
+ pug-walk "^2.0.0"
+
+pug-load@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz"
+ integrity sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==
+ dependencies:
+ object-assign "^4.1.1"
+ pug-walk "^2.0.0"
+
+pug-parser@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz"
+ integrity sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==
+ dependencies:
+ pug-error "^2.0.0"
+ token-stream "1.0.0"
+
+pug-runtime@^3.0.0, pug-runtime@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz"
+ integrity sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==
+
+pug-strip-comments@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz"
+ integrity sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==
+ dependencies:
+ pug-error "^2.0.0"
+
+pug-walk@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz"
+ integrity sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==
+
+pug@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz"
+ integrity sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==
+ dependencies:
+ pug-code-gen "^3.0.2"
+ pug-filters "^4.0.0"
+ pug-lexer "^5.0.1"
+ pug-linker "^4.0.0"
+ pug-load "^3.0.0"
+ pug-parser "^6.0.0"
+ pug-runtime "^3.0.1"
+ pug-strip-comments "^2.0.0"
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+read-cache@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz"
+ integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
+ dependencies:
+ pify "^2.3.0"
+
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+ dependencies:
+ picomatch "^2.2.1"
+
+request-light@^0.5.4:
+ version "0.5.8"
+ resolved "https://registry.npmjs.org/request-light/-/request-light-0.5.8.tgz"
+ integrity sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==
+
+resolve@^1.1.7, resolve@^1.15.1, resolve@^1.22.0, resolve@^1.22.2:
+ version "1.22.8"
+ resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz"
+ integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
+ dependencies:
+ is-core-module "^2.13.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+"rollup@>=2.59.0 <2.78.0":
+ version "2.77.3"
+ resolved "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz"
+ integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+semver@^7.3.5:
+ version "7.5.4"
+ resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+ dependencies:
+ lru-cache "^6.0.0"
+
+set-function-length@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz"
+ integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==
+ dependencies:
+ define-data-property "^1.1.1"
+ get-intrinsic "^1.2.1"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.0"
+
+source-map-js@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
+ integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
+sucrase@^3.32.0:
+ version "3.34.0"
+ resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz"
+ integrity sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.2"
+ commander "^4.0.0"
+ glob "7.1.6"
+ lines-and-columns "^1.1.6"
+ mz "^2.7.0"
+ pirates "^4.0.1"
+ ts-interface-checker "^0.1.9"
+
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+tailwindcss@^3.0.23, tailwindcss@^3.3.5:
+ version "3.3.5"
+ resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz"
+ integrity sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==
+ dependencies:
+ "@alloc/quick-lru" "^5.2.0"
+ arg "^5.0.2"
+ chokidar "^3.5.3"
+ didyoumean "^1.2.2"
+ dlv "^1.1.3"
+ fast-glob "^3.3.0"
+ glob-parent "^6.0.2"
+ is-glob "^4.0.3"
+ jiti "^1.19.1"
+ lilconfig "^2.1.0"
+ micromatch "^4.0.5"
+ normalize-path "^3.0.0"
+ object-hash "^3.0.0"
+ picocolors "^1.0.0"
+ postcss "^8.4.23"
+ postcss-import "^15.1.0"
+ postcss-js "^4.0.1"
+ postcss-load-config "^4.0.1"
+ postcss-nested "^6.0.1"
+ postcss-selector-parser "^6.0.11"
+ resolve "^1.22.2"
+ sucrase "^3.32.0"
+
+thenify-all@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz"
+ integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==
+ dependencies:
+ thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+ version "3.3.1"
+ resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz"
+ integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
+ dependencies:
+ any-promise "^1.0.0"
+
+to-fast-properties@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz"
+ integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+token-stream@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz"
+ integrity sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==
+
+ts-interface-checker@^0.1.9:
+ version "0.1.13"
+ resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz"
+ integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
+
+typescript@^4.4.4:
+ version "4.9.5"
+ resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz"
+ integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
+
+upath@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz"
+ integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==
+
+update-browserslist-db@^1.0.13:
+ version "1.0.13"
+ resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz"
+ integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
+ dependencies:
+ escalade "^3.1.1"
+ picocolors "^1.0.0"
+
+util-deprecate@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+vitawind@^2.0.0:
+ version "2.2.4"
+ resolved "https://registry.npmjs.org/vitawind/-/vitawind-2.2.4.tgz"
+ integrity sha512-XHEavMf9OjLfR8ahNjfyEoO8SEzRqfbCBf81MBCQ6HhU2ra1tBiJKTqDuOgGOsMugOeu/ap1A4rARUjv4E1q+Q==
+ dependencies:
+ autoprefixer "^10.4.2"
+ postcss "^8.4.8"
+ tailwindcss "^3.0.23"
+
+vite@^2.7.2:
+ version "2.9.16"
+ resolved "https://registry.npmjs.org/vite/-/vite-2.9.16.tgz"
+ integrity sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA==
+ dependencies:
+ esbuild "^0.14.27"
+ postcss "^8.4.13"
+ resolve "^1.22.0"
+ rollup ">=2.59.0 <2.78.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+void-elements@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz"
+ integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==
+
+vscode-css-languageservice@^5.1.7:
+ version "5.4.2"
+ resolved "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-5.4.2.tgz"
+ integrity sha512-DT7+7vfdT2HDNjDoXWtYJ0lVDdeDEdbMNdK4PKqUl2MS8g7PWt7J5G9B6k9lYox8nOfhCEjLnoNC3UKHHCR1lg==
+ dependencies:
+ vscode-languageserver-textdocument "^1.0.4"
+ vscode-languageserver-types "^3.16.0"
+ vscode-nls "^5.0.0"
+ vscode-uri "^3.0.3"
+
+vscode-html-languageservice@^4.1.0:
+ version "4.2.5"
+ resolved "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-4.2.5.tgz"
+ integrity sha512-dbr10KHabB9EaK8lI0XZW7SqOsTfrNyT3Nuj0GoPi4LjGKUmMiLtsqzfedIzRTzqY+w0FiLdh0/kQrnQ0tLxrw==
+ dependencies:
+ vscode-languageserver-textdocument "^1.0.4"
+ vscode-languageserver-types "^3.16.0"
+ vscode-nls "^5.0.0"
+ vscode-uri "^3.0.3"
+
+vscode-json-languageservice@^4.1.8:
+ version "4.2.1"
+ resolved "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz"
+ integrity sha512-xGmv9QIWs2H8obGbWg+sIPI/3/pFgj/5OWBhNzs00BkYQ9UaB2F6JJaGB/2/YOZJ3BvLXQTC4Q7muqU25QgAhA==
+ dependencies:
+ jsonc-parser "^3.0.0"
+ vscode-languageserver-textdocument "^1.0.3"
+ vscode-languageserver-types "^3.16.0"
+ vscode-nls "^5.0.0"
+ vscode-uri "^3.0.3"
+
+vscode-jsonrpc@8.1.0:
+ version "8.1.0"
+ resolved "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz"
+ integrity sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==
+
+vscode-jsonrpc@^8.0.0-next.2:
+ version "8.2.0"
+ resolved "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz"
+ integrity sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==
+
+vscode-languageserver-protocol@3.17.3:
+ version "3.17.3"
+ resolved "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz"
+ integrity sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==
+ dependencies:
+ vscode-jsonrpc "8.1.0"
+ vscode-languageserver-types "3.17.3"
+
+vscode-languageserver-textdocument@^1.0.1, vscode-languageserver-textdocument@^1.0.3, vscode-languageserver-textdocument@^1.0.4:
+ version "1.0.11"
+ resolved "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz"
+ integrity sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==
+
+vscode-languageserver-types@3.17.3:
+ version "3.17.3"
+ resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz"
+ integrity sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==
+
+vscode-languageserver-types@^3.15.1, vscode-languageserver-types@^3.16.0:
+ version "3.17.5"
+ resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz"
+ integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==
+
+vscode-languageserver@^8.0.0-next.2:
+ version "8.1.0"
+ resolved "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.1.0.tgz"
+ integrity sha512-eUt8f1z2N2IEUDBsKaNapkz7jl5QpskN2Y0G01T/ItMxBxw1fJwvtySGB9QMecatne8jFIWJGWI61dWjyTLQsw==
+ dependencies:
+ vscode-languageserver-protocol "3.17.3"
+
+vscode-nls@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz"
+ integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==
+
+vscode-pug-languageservice@0.29.8:
+ version "0.29.8"
+ resolved "https://registry.npmjs.org/vscode-pug-languageservice/-/vscode-pug-languageservice-0.29.8.tgz"
+ integrity sha512-QHYAzDSJLg7GOLxCZ12qsM0dAM0dPeMSS1t4kKfzLsfpErmZpFzkAIXbidVrNMdMffGZMtTuIlcpEyWHbx96Iw==
+ dependencies:
+ "@volar/code-gen" "0.29.8"
+ "@volar/shared" "0.29.8"
+ "@volar/source-map" "0.29.8"
+ "@volar/transforms" "0.29.8"
+ pug-lexer "^5.0.1"
+ pug-parser "^6.0.0"
+ vscode-languageserver "^8.0.0-next.2"
+
+vscode-typescript-languageservice@0.29.8:
+ version "0.29.8"
+ resolved "https://registry.npmjs.org/vscode-typescript-languageservice/-/vscode-typescript-languageservice-0.29.8.tgz"
+ integrity sha512-eecDqHk4WjEvy6VHQ6teHczppQ9yJO2wExCy7yu7WiFj35qbw0h4G6Erv46MvP3ClL8FggFzD7s1qM6vdqJUfw==
+ dependencies:
+ "@volar/shared" "0.29.8"
+ semver "^7.3.5"
+ upath "^2.0.1"
+ vscode-languageserver "^8.0.0-next.2"
+ vscode-languageserver-textdocument "^1.0.1"
+
+vscode-uri@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.1.2.tgz"
+ integrity sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==
+
+vscode-uri@^3.0.2, vscode-uri@^3.0.3:
+ version "3.0.8"
+ resolved "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz"
+ integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==
+
+vscode-vue-languageservice@0.29.8:
+ version "0.29.8"
+ resolved "https://registry.npmjs.org/vscode-vue-languageservice/-/vscode-vue-languageservice-0.29.8.tgz"
+ integrity sha512-qSJdvW5ttyGUB/8uWDKgo8vnIoFnXYlBP4Z/cn54btsRn6ZMw7IJGJU1381e7p/yGvMTLeGbugD53SghbnSa6g==
+ dependencies:
+ "@volar/code-gen" "0.29.8"
+ "@volar/html2pug" "0.29.8"
+ "@volar/shared" "0.29.8"
+ "@volar/source-map" "0.29.8"
+ "@volar/transforms" "0.29.8"
+ "@volar/vue-code-gen" "0.29.8"
+ "@vscode/emmet-helper" "^2.8.0"
+ "@vue/reactivity" "^3.2.21"
+ "@vue/shared" "^3.2.21"
+ request-light "^0.5.4"
+ upath "^2.0.1"
+ vscode-css-languageservice "^5.1.7"
+ vscode-html-languageservice "^4.1.0"
+ vscode-json-languageservice "^4.1.8"
+ vscode-languageserver "^8.0.0-next.2"
+ vscode-languageserver-textdocument "^1.0.1"
+ vscode-pug-languageservice "0.29.8"
+ vscode-typescript-languageservice "0.29.8"
+
+vue-tsc@^0.29.8:
+ version "0.29.8"
+ resolved "https://registry.npmjs.org/vue-tsc/-/vue-tsc-0.29.8.tgz"
+ integrity sha512-pT0wLRjvRuSmB+J4WJT6uuV9mO0KtSSXEAtaVXZQzyk5+DJdbLIQTbRce/TXSkfqt1l1WogO78RjtOJFiMCgfQ==
+ dependencies:
+ "@volar/shared" "0.29.8"
+ vscode-vue-languageservice "0.29.8"
+
+vue@^3.2.25:
+ version "3.3.7"
+ resolved "https://registry.npmjs.org/vue/-/vue-3.3.7.tgz"
+ integrity sha512-YEMDia1ZTv1TeBbnu6VybatmSteGOS3A3YgfINOfraCbf85wdKHzscD6HSS/vB4GAtI7sa1XPX7HcQaJ1l24zA==
+ dependencies:
+ "@vue/compiler-dom" "3.3.7"
+ "@vue/compiler-sfc" "3.3.7"
+ "@vue/runtime-dom" "3.3.7"
+ "@vue/server-renderer" "3.3.7"
+ "@vue/shared" "3.3.7"
+
+with@^7.0.0:
+ version "7.0.2"
+ resolved "https://registry.npmjs.org/with/-/with-7.0.2.tgz"
+ integrity sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==
+ dependencies:
+ "@babel/parser" "^7.9.6"
+ "@babel/types" "^7.9.6"
+ assert-never "^1.2.1"
+ babel-walk "3.0.0-canary-5"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yaml@^2.1.1:
+ version "2.3.3"
+ resolved "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz"
+ integrity sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==
diff --git a/afb/afb/asgi.py b/afb/afb/asgi.py
index 71efab67..78517635 100644
--- a/afb/afb/asgi.py
+++ b/afb/afb/asgi.py
@@ -11,6 +11,6 @@
from django.core.asgi import get_asgi_application
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'afb.settings')
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "afb.settings")
application = get_asgi_application()
diff --git a/afb/afb/settings.py b/afb/afb/settings.py
index 37c86d45..64cfda96 100644
--- a/afb/afb/settings.py
+++ b/afb/afb/settings.py
@@ -1,4 +1,3 @@
-
"""
Django settings for afb project.
@@ -21,7 +20,7 @@
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = 'django-insecure-k3nma!u)7oz(lt346n-=rx=rt%u_^j8-rdz3p(y3o$ot0%soqh'
+SECRET_KEY = "django-insecure-k3nma!u)7oz(lt346n-=rx=rt%u_^j8-rdz3p(y3o$ot0%soqh"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
@@ -33,20 +32,20 @@
#
INSTALLED_APPS = [
- 'unfold', # https://github.com/unfoldadmin/django-unfold
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'phonenumber_field',
- 'crispy_forms',
- 'tailwind',
+ "unfold", # https://github.com/unfoldadmin/django-unfold
+ "django.contrib.admin",
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.messages",
+ "django.contrib.staticfiles",
+ "phonenumber_field",
+ "crispy_forms",
+ "tailwind",
"crispy_tailwind",
- 'theme', # python manage.py tailwind init
- 'afbcore',
- 'django_browser_reload',
+ "theme", # python manage.py tailwind init
+ "afbcore",
+ "django_browser_reload",
]
# https://github.com/django-crispy-forms/crispy-tailwind
@@ -57,35 +56,34 @@
PHONENUMBER_DB_FORMAT = "INTERNATIONAL"
PHONENUMBER_DEFAULT_FORMAT = "E164"
-PHONENUMBER_DEFAULT_REGION = 'CA'
-
+PHONENUMBER_DEFAULT_REGION = "CA"
MIDDLEWARE = [
- 'django.middleware.security.SecurityMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
- 'django_browser_reload.middleware.BrowserReloadMiddleware'
+ "django.middleware.security.SecurityMiddleware",
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.middleware.common.CommonMiddleware",
+ "django.middleware.csrf.CsrfViewMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "django.contrib.messages.middleware.MessageMiddleware",
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
+ "django_browser_reload.middleware.BrowserReloadMiddleware",
]
-ROOT_URLCONF = 'afb.urls'
+ROOT_URLCONF = "afb.urls"
# Django-Tailwind
# https://django-tailwind.readthedocs.io/en/latest/installation.html#configuration
-TAILWIND_APP_NAME = 'theme'
+TAILWIND_APP_NAME = "theme"
-AUTH_USER_MODEL = 'afbcore.User'
+AUTH_USER_MODEL = "afbcore.User"
INTERNAL_IPS = [
# Add local IP addresses here for tailwind to work, then run:
# * (Dev) `python manage.py tailwind install`
# * (Production) `python manage.py tailwind build`
- '127.0.0.1',
+ "127.0.0.1",
]
# Templates
@@ -93,30 +91,30 @@
TEMPLATES = [
{
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [],
- 'APP_DIRS': True,
- 'OPTIONS': {
- 'context_processors': [
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [],
+ "APP_DIRS": True,
+ "OPTIONS": {
+ "context_processors": [
+ "django.template.context_processors.debug",
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
],
},
},
]
-WSGI_APPLICATION = 'afb.wsgi.application'
+WSGI_APPLICATION = "afb.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': BASE_DIR / 'db.sqlite3',
+ "default": {
+ "ENGINE": "django.db.backends.sqlite3",
+ "NAME": BASE_DIR / "db.sqlite3",
}
}
@@ -126,16 +124,16 @@
AUTH_PASSWORD_VALIDATORS = [
{
- 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
- 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
- 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
- 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
@@ -143,9 +141,9 @@
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
-LANGUAGE_CODE = 'en-us'
+LANGUAGE_CODE = "en-us"
-TIME_ZONE = 'UTC'
+TIME_ZONE = "UTC"
USE_I18N = True
@@ -158,7 +156,7 @@
# For prod:
# https://docs.djangoproject.com/en/4.2/howto/static-files/deployment/#staticfiles-from-cdn
# https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-STORAGES
-STATIC_URL = 'static/'
+STATIC_URL = "static/"
STATICFILES_DIRS = [
# BASE_DIR / "static",
@@ -170,4 +168,4 @@
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
-DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
+DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
diff --git a/afb/afb/urls.py b/afb/afb/urls.py
index 2fe62b45..bb973e02 100644
--- a/afb/afb/urls.py
+++ b/afb/afb/urls.py
@@ -1,4 +1,4 @@
-'''
+"""
URL configuration for afb project.
The `urlpatterns` list routes URLs to views. For more information please see:
@@ -13,7 +13,7 @@
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
-'''
+"""
from django.contrib import admin
from django.urls import include, path
@@ -21,20 +21,14 @@
from afbcore.views import ClientRequestView
urlpatterns = [
- path('admin/', admin.site.urls),
-
- path('dashboard', DashboardView.as_view(), name='dashboard'),
- path('', DashboardView.as_view()),
-
- path('join/', ClientSignupFormView.as_view()),
-
+ path("admin/", admin.site.urls),
+ path("dashboard", DashboardView.as_view(), name="dashboard"),
+ path("", DashboardView.as_view()),
+ path("join/", ClientSignupFormView.as_view()),
# Part of django-tailwind
# See https://django-tailwind.readthedocs.io/en/latest/installation.html#configuration
- path('__reload__/', include('django_browser_reload.urls')),
-
- path('request/', ClientRequestView.as_view(), name='create_request'),
-
- path('login/', MyLoginView.as_view(), name='login'),
-
- path('about/', AboutView.as_view()),
+ path("__reload__/", include("django_browser_reload.urls")),
+ path("request/", ClientRequestView.as_view(), name="create_request"),
+ path("login/", MyLoginView.as_view(), name="login"),
+ path("about/", AboutView.as_view()),
]
diff --git a/afb/afbcore/admin.py b/afb/afbcore/admin.py
index 47589575..f0f74f60 100644
--- a/afb/afbcore/admin.py
+++ b/afb/afbcore/admin.py
@@ -1,4 +1,3 @@
-
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Client, Manager, Volunteer, User
diff --git a/afb/afbcore/forms/client.py b/afb/afbcore/forms/client.py
index b13bfcb2..7a8ac2fd 100644
--- a/afb/afbcore/forms/client.py
+++ b/afb/afbcore/forms/client.py
@@ -1,12 +1,9 @@
-
-
from django.forms import ModelForm
from afbcore.models import Client
class ClientSignupForm(ModelForm):
-
class Meta:
model = Client
fields = [
diff --git a/afb/afbcore/models/__init__.py b/afb/afbcore/models/__init__.py
index 51f49d66..9e9b412e 100644
--- a/afb/afbcore/models/__init__.py
+++ b/afb/afbcore/models/__init__.py
@@ -1,5 +1,3 @@
-
-
from django.db import models
from .branch import Branch # noqa
diff --git a/afb/afbcore/models/branch.py b/afb/afbcore/models/branch.py
index 6a36bc1f..483a35aa 100644
--- a/afb/afbcore/models/branch.py
+++ b/afb/afbcore/models/branch.py
@@ -1,13 +1,15 @@
-
import uuid
from django.db import models
+
class Branch(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# Location Name ie Winnipeg, MB; Medicine Hat, AB etc.
- location_name = models.CharField(max_length=255, help_text="ie Winnipeg, MB; Medicine Hat, AB etc.")
+ location_name = models.CharField(
+ max_length=255, help_text="ie Winnipeg, MB; Medicine Hat, AB etc."
+ )
# Postal/Zip Code Range start with Canada but the intent is to
# use this in the USA which may be more apt to paying
@@ -34,14 +36,14 @@ class Branch(models.Model):
# Delivery Type Drop off and/or pick up options
delivery_type = models.CharField(max_length=255)
- # Delivery deadline in days
+ # Delivery deadline in days
delivery_deadline_days = models.IntegerField(default=3)
# Type of delivery service, 'Drop off' or 'Pick up'
delivery_type = models.CharField(
max_length=24,
- choices=[('drop_off', 'Drop off'), ('pick_up', 'Pick up')],
- default='Drop off',
+ choices=[("drop_off", "Drop off"), ("pick_up", "Pick up")],
+ default="Drop off",
)
# Delivery/pickup More details
@@ -51,4 +53,4 @@ class Branch(models.Model):
blurb = models.TextField(blank=True)
# Blurb image A picture to go along with the blurb
- blurb_image = models.ImageField(upload_to='branch_images/', blank=True, null=True)
+ blurb_image = models.ImageField(upload_to="branch_images/", blank=True, null=True)
diff --git a/afb/afbcore/models/client.py b/afb/afbcore/models/client.py
index b13bfcb2..7a8ac2fd 100644
--- a/afb/afbcore/models/client.py
+++ b/afb/afbcore/models/client.py
@@ -1,12 +1,9 @@
-
-
from django.forms import ModelForm
from afbcore.models import Client
class ClientSignupForm(ModelForm):
-
class Meta:
model = Client
fields = [
diff --git a/afb/afbcore/models/delivery.py b/afb/afbcore/models/delivery.py
index 6f2ed335..4082928d 100644
--- a/afb/afbcore/models/delivery.py
+++ b/afb/afbcore/models/delivery.py
@@ -1,4 +1,3 @@
-
import uuid
from django.db import models
@@ -6,7 +5,9 @@
class DeliveryRegion(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
- name = models.CharField(max_length=255, help_text="Name of the region (e.g. postal code, city, or area)")
+ name = models.CharField(
+ max_length=255, help_text="Name of the region (e.g. postal code, city, or area)"
+ )
description = models.TextField(blank=True)
def __str__(self):
@@ -18,7 +19,6 @@ class Delivery(models.Model):
food_available = models.ForeignKey("FoodAvailable", on_delete=models.DO_NOTHING)
-
delivery_date = models.DateField()
delivery_time = models.TimeField()
diff --git a/afb/afbcore/models/food_available.py b/afb/afbcore/models/food_available.py
index a83f27a0..520b412b 100644
--- a/afb/afbcore/models/food_available.py
+++ b/afb/afbcore/models/food_available.py
@@ -5,10 +5,11 @@
from django.db import models
from enum import Enum
+
class PetType(Enum):
- CAT = 'Cat'
- DOG = 'Dog'
- OTHER = 'Other'
+ CAT = "Cat"
+ DOG = "Dog"
+ OTHER = "Other"
class FoodAvailable(models.Model):
@@ -34,10 +35,13 @@ class FoodAvailable(models.Model):
Total Cat Wet
Total Dog Dry
Total Dog Wet
- """
+ """
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=255)
- pet_type = models.CharField(max_length=255, choices=[(pet_type.value, pet_type.value) for pet_type in PetType])
+ pet_type = models.CharField(
+ max_length=255,
+ choices=[(pet_type.value, pet_type.value) for pet_type in PetType],
+ )
food_type = models.CharField(max_length=255)
food_amount = models.CharField(max_length=255)
diff --git a/afb/afbcore/models/pet.py b/afb/afbcore/models/pet.py
index f10b9eb3..ed6faa2a 100644
--- a/afb/afbcore/models/pet.py
+++ b/afb/afbcore/models/pet.py
@@ -1,9 +1,9 @@
-
import uuid
from enum import Enum
from django.db import models
+
class PetSize(Enum):
TOY = "Toy - up to 10lbs"
SMALL_BREED = "Small Breed - 10-20 lbs"
@@ -22,42 +22,47 @@ class WeightRange(Enum):
class Pet(models.Model):
- """
- Pet model to store information about pets belonging to clients.
+ """
+ Pet model to store information about pets belonging to clients.
+
+ The maximum number of pet profiles that would be allowed
+ to be created would be deteremined from the Branch
+ setting of "Number of Pet's Serviced/Houeshold" above
- The maximum number of pet profiles that would be allowed
- to be created would be deteremined from the Branch
- setting of "Number of Pet's Serviced/Houeshold" above
+ """
- """
- id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
- # Client - Foreign Key
- client = models.ForeignKey("Client", on_delete=models.CASCADE)
+ # Client - Foreign Key
+ client = models.ForeignKey("Client", on_delete=models.CASCADE)
- # Name
- name = models.CharField(max_length=255)
+ # Name
+ name = models.CharField(max_length=255)
- # DOB - I'd like to system to record the date of birth and then use it to calculate real time age
- dob = models.DateField()
+ # DOB - I'd like to system to record the date of birth and then use it to calculate real time age
+ dob = models.DateField()
- # Size - Drop down list with size options
- size = models.CharField(max_length=32, choices=[(size.name, size.value) for size in PetSize])
+ # Size - Drop down list with size options
+ size = models.CharField(
+ max_length=32, choices=[(size.name, size.value) for size in PetSize]
+ )
- # Weight - Drop down list with weight ranges (this is typically only needed for dogs). Select one.
- weight = models.CharField(max_length=32, choices=[(size.name, size.value) for size in WeightRange])
+ # Weight - Drop down list with weight ranges (this is typically only needed for dogs). Select one.
+ weight = models.CharField(
+ max_length=32, choices=[(size.name, size.value) for size in WeightRange]
+ )
- # Usual Food Brands - Free form
- usual_food_brands = models.TextField(blank=True)
+ # Usual Food Brands - Free form
+ usual_food_brands = models.TextField(blank=True)
- # Allergies - Yes/No
- allergies = models.BooleanField(default=False)
+ # Allergies - Yes/No
+ allergies = models.BooleanField(default=False)
- # Allergies Type - Drop down list with an "other" option that is free form text. Select all that apply
- allergy_types = models.TextField(blank=True)
+ # Allergies Type - Drop down list with an "other" option that is free form text. Select all that apply
+ allergy_types = models.TextField(blank=True)
- # Pictures - For no reason other than I think it would be fun to have their client dashboard have pics of their pets for the profiles
- pictures = models.ImageField(upload_to="pet_pictures/", null=True, blank=True)
+ # Pictures - For no reason other than I think it would be fun to have their client dashboard have pics of their pets for the profiles
+ pictures = models.ImageField(upload_to="pet_pictures/", null=True, blank=True)
- def __str__(self):
- return self.name
+ def __str__(self):
+ return self.name
diff --git a/afb/afbcore/models/pet_request.py b/afb/afbcore/models/pet_request.py
index 8acda1e6..6f5818dd 100644
--- a/afb/afbcore/models/pet_request.py
+++ b/afb/afbcore/models/pet_request.py
@@ -1,4 +1,3 @@
-
# PetRequest
import uuid
@@ -7,67 +6,68 @@
STATUS_CHOICES = [
- ('received', 'Request Received'),
- ('approved', 'Request Approved & in Queue'),
- ('denied', 'Request Denied'),
- ('assigned', 'Volunteer Assigned'),
- ('ready_for_pickup', 'Request Ready For Volunteer Pickup'),
- ('scheduled', 'Delivery Scheduled'),
- ('out_for_delivery', 'Out For Delivery'),
- ('delivered', 'Delivered'),
- ('undeliverable', 'Undeliverable'),
+ ("received", "Request Received"),
+ ("approved", "Request Approved & in Queue"),
+ ("denied", "Request Denied"),
+ ("assigned", "Volunteer Assigned"),
+ ("ready_for_pickup", "Request Ready For Volunteer Pickup"),
+ ("scheduled", "Delivery Scheduled"),
+ ("out_for_delivery", "Out For Delivery"),
+ ("delivered", "Delivered"),
+ ("undeliverable", "Undeliverable"),
]
class PetRequest(models.Model):
- id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
-
- client = models.ForeignKey("Client", on_delete=models.DO_NOTHING)
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
- branch = models.ForeignKey("Branch", on_delete=models.DO_NOTHING)
+ client = models.ForeignKey("Client", on_delete=models.DO_NOTHING)
- # One or more. ** We will want them to see and confirm/edit their address and phone number on the request, and be able to see pets, and edit some fields of their pets info
- pets = models.ManyToManyField("Pet")
+ branch = models.ForeignKey("Branch", on_delete=models.DO_NOTHING)
- # Yes/No - No requires them to edit address and ensure that it's not attached to another client or then both clients need to be on hold to review
- confirm_address = models.BooleanField()
+ # One or more. ** We will want them to see and confirm/edit their address and phone number on the request, and be able to see pets, and edit some fields of their pets info
+ pets = models.ManyToManyField("Pet")
- # Yes/No - No requires them to update phone number (validate format)
- confirm_phone_number = models.BooleanField()
+ # Yes/No - No requires them to edit address and ensure that it's not attached to another client or then both clients need to be on hold to review
+ confirm_address = models.BooleanField()
- # Agree to Terms and Conditions
- agreed_to_terms = models.BooleanField()
+ # Yes/No - No requires them to update phone number (validate format)
+ confirm_phone_number = models.BooleanField()
- # Text or Phone
- method_of_contact = models.CharField(max_length=100)
+ # Agree to Terms and Conditions
+ agreed_to_terms = models.BooleanField()
- # Drop down list with an "other" option that is free form text. Select all that apply.
- food_types_available = models.ManyToManyField("FoodAvailable")
+ # Text or Phone
+ method_of_contact = models.CharField(max_length=100)
- # Use system date - do not let clients input/edit. We like to have deliveries made within the branches delivery window so would be great if we could send notifications when requests are "aging"
- date_requested = models.DateField(auto_now_add=True)
+ # Drop down list with an "other" option that is free form text. Select all that apply.
+ food_types_available = models.ManyToManyField("FoodAvailable")
- # Yes/No
- safe_drop = models.BooleanField()
+ # Use system date - do not let clients input/edit. We like to have deliveries made within the branches delivery window so would be great if we could send notifications when requests are "aging"
+ date_requested = models.DateField(auto_now_add=True)
- # Free form comments from client - set max character limit
- request_notes = models.TextField(max_length=255)
+ # Yes/No
+ safe_drop = models.BooleanField()
- # Request Received, Request Approved & in Queue, Request Denied, Volunteer Assigned, Request Ready For Volunteer Pickup, Delivery Scheduled, Out For Delivery, Delivered, Undeliverable
- status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='received')
+ # Free form comments from client - set max character limit
+ request_notes = models.TextField(max_length=255)
- # Driver comments
- driver_comments = models.TextField(max_length=255, null=True, blank=True)
+ # Request Received, Request Approved & in Queue, Request Denied, Volunteer Assigned, Request Ready For Volunteer Pickup, Delivery Scheduled, Out For Delivery, Delivered, Undeliverable
+ status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="received")
- # Picture of delivery
- picture_of_delivery = models.ImageField(upload_to="delivery_pictures/", null=True, blank=True)
+ # Driver comments
+ driver_comments = models.TextField(max_length=255, null=True, blank=True)
- # Not sure what to call this one, but if the volunteer has an issue with the client - they are rude or aggressive for example, can we allow the driver to mark the client as suspended and admin to review?
- needs_review = models.BooleanField()
+ # Picture of delivery
+ picture_of_delivery = models.ImageField(
+ upload_to="delivery_pictures/", null=True, blank=True
+ )
+ # Not sure what to call this one, but if the volunteer has an issue with the client - they are rude or aggressive for example, can we allow the driver to mark the client as suspended and admin to review?
+ needs_review = models.BooleanField()
- def __str__(self):
- return f"Pet Request {self.id}"
+ def __str__(self):
+ return f"Pet Request {self.id}"
- class Meta:
- ordering = ['-date_requested']
+ class Meta:
+ ordering = ["-date_requested"]
diff --git a/afb/afbcore/models/users/__init__.py b/afb/afbcore/models/users/__init__.py
index 60808e88..4bd242ef 100644
--- a/afb/afbcore/models/users/__init__.py
+++ b/afb/afbcore/models/users/__init__.py
@@ -1,5 +1,3 @@
-
-
from .client import Client
from .manager import Manager
from .volunteer import Volunteer
diff --git a/afb/afbcore/models/users/base_profile.py b/afb/afbcore/models/users/base_profile.py
index 1d9bf16a..00420417 100644
--- a/afb/afbcore/models/users/base_profile.py
+++ b/afb/afbcore/models/users/base_profile.py
@@ -1,4 +1,3 @@
-
import uuid
from django.db import models
@@ -11,14 +10,13 @@
# Define default arguments for ManyToManyField
many_to_many_defaults = {
- 'related_name': '+',
- 'blank': True,
- 'symmetrical': False,
+ "related_name": "+",
+ "blank": True,
+ "symmetrical": False,
}
class BaseProfile(models.Model):
-
class Meta:
abstract = True
@@ -42,7 +40,7 @@ class Meta:
phone_number = PhoneNumberField(
blank=True,
null=True,
- region='US',
+ region="US",
max_length=20,
)
diff --git a/afb/afbcore/models/users/client.py b/afb/afbcore/models/users/client.py
index 2fa5e0b6..790c4102 100644
--- a/afb/afbcore/models/users/client.py
+++ b/afb/afbcore/models/users/client.py
@@ -1,4 +1,3 @@
-
import uuid
from django.db import models
@@ -9,37 +8,34 @@
# Status - Active, On Hold, Banned
STATUS_CHOICES = [
- ('active', 'Active'),
- ('on_hold', 'On Hold'),
- ('banned', 'Banned'),
+ ("active", "Active"),
+ ("on_hold", "On Hold"),
+ ("banned", "Banned"),
]
-
class Client(BaseProfile):
- """
- Clients could try to scam and create duplicate accounts to circumvent frequency, change pet info, etc.
- We need to do our best to ensure each account is unique.
- """
-
- # Address - If address is duplicate to another clients, both accounts need to be placed on hold and manually reviewed/approved bc people are scammers.
- # Has to be a validated address (google?) and not permitted to be overwritten. The last amount of free form text entry as possible.
- # You'd be amazed how many clients don't know their postal code and we route by postal code sooooo
-
+ """
+ Clients could try to scam and create duplicate accounts to circumvent frequency, change pet info, etc.
+ We need to do our best to ensure each account is unique.
+ """
- # Postal/Zip Code - Has to be a validated address (google?) and not permitted to be overwritten. The last amount of free form text entry as possible.
- # You'd be amazed how many clients don't know their postal code and we route by postal code sooooo
- validated_postal_code = models.CharField(max_length=20, null=True)
+ # Address - If address is duplicate to another clients, both accounts need to be placed on hold and manually reviewed/approved bc people are scammers.
+ # Has to be a validated address (google?) and not permitted to be overwritten. The last amount of free form text entry as possible.
+ # You'd be amazed how many clients don't know their postal code and we route by postal code sooooo
- # Country - I don't know if we need this but google addresses populate country too. It may be useful for analytics
- country = models.CharField(max_length=255, blank=True)
+ # Postal/Zip Code - Has to be a validated address (google?) and not permitted to be overwritten. The last amount of free form text entry as possible.
+ # You'd be amazed how many clients don't know their postal code and we route by postal code sooooo
+ validated_postal_code = models.CharField(max_length=20, null=True)
- status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active')
+ # Country - I don't know if we need this but google addresses populate country too. It may be useful for analytics
+ country = models.CharField(max_length=255, blank=True)
+ status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="active")
- def __str__(self):
- return f"{self.first_name} {self.last_name}"
+ def __str__(self):
+ return f"{self.first_name} {self.last_name}"
- def get_absolute_url(self):
- return reverse("client-create", kwargs={"pk": self.pk})
+ def get_absolute_url(self):
+ return reverse("client-create", kwargs={"pk": self.pk})
diff --git a/afb/afbcore/models/users/manager.py b/afb/afbcore/models/users/manager.py
index c9f4b5c5..a7e8ac83 100644
--- a/afb/afbcore/models/users/manager.py
+++ b/afb/afbcore/models/users/manager.py
@@ -1,4 +1,3 @@
-
import uuid
from django.db import models
@@ -7,13 +6,13 @@
class Manager(BaseProfile):
- """
- """
+ """ """
+
+ role_level = models.IntegerField()
- role_level = models.IntegerField()
+ def __str__(self):
+ return f"{self.first_name} {self.last_name}"
- def __str__(self):
- return f"{self.first_name} {self.last_name}"
"""
GitHub Copilot: Here are all the arguments that can be used with Django's `ManyToManyField`:
diff --git a/afb/afbcore/models/users/user.py b/afb/afbcore/models/users/user.py
index 909f6d35..dd406742 100644
--- a/afb/afbcore/models/users/user.py
+++ b/afb/afbcore/models/users/user.py
@@ -1,9 +1,8 @@
-
-
import uuid
from django.db import models
from django.contrib.auth.models import AbstractUser
+
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
diff --git a/afb/afbcore/models/users/volunteer.py b/afb/afbcore/models/users/volunteer.py
index 34ac5598..9ad4d68d 100644
--- a/afb/afbcore/models/users/volunteer.py
+++ b/afb/afbcore/models/users/volunteer.py
@@ -1,4 +1,3 @@
-
import uuid
from django.db import models
@@ -22,6 +21,5 @@ class Volunteer(BaseProfile):
# For each delivery made/attempted - redeem these for swag/gift cards
points_earned = models.IntegerField(default=0)
-
def __str__(self):
- return f"{self.first_name} {self.last_name}"
+ return f"{self.first_name} {self.last_name}"
diff --git a/afb/afbcore/public/img/favicons/browserconfig.xml b/afb/afbcore/public/img/favicons/browserconfig.xml
index c5541482..7d453d3b 100644
--- a/afb/afbcore/public/img/favicons/browserconfig.xml
+++ b/afb/afbcore/public/img/favicons/browserconfig.xml
@@ -1,2 +1,2 @@
-#ffffff
\ No newline at end of file
+#ffffff
diff --git a/afb/afbcore/public/img/favicons/manifest.json b/afb/afbcore/public/img/favicons/manifest.json
index 013d4a6a..758f8d2a 100644
--- a/afb/afbcore/public/img/favicons/manifest.json
+++ b/afb/afbcore/public/img/favicons/manifest.json
@@ -38,4 +38,4 @@
"density": "4.0"
}
]
-}
\ No newline at end of file
+}
diff --git a/afb/afbcore/views/__init__.py b/afb/afbcore/views/__init__.py
index cf0b9e34..868df5ee 100644
--- a/afb/afbcore/views/__init__.py
+++ b/afb/afbcore/views/__init__.py
@@ -1,12 +1,15 @@
-
-
from .client import *
-from .dashboard import (ClientDashboardView, DashboardRouterView,
- ManagerDashboardView, VolunteerDashboardView)
+from .dashboard import (
+ ClientDashboardView,
+ DashboardRouterView,
+ ManagerDashboardView,
+ VolunteerDashboardView,
+)
from django.contrib.auth.views import LoginView
from django.urls import reverse_lazy
+
class MyLoginView(LoginView):
- template_name = 'afbcore/login.html'
- success_url = reverse_lazy('afbcore:dashboard')
+ template_name = "afbcore/login.html"
+ success_url = reverse_lazy("afbcore:dashboard")
diff --git a/afb/afbcore/views/dashboard.py b/afb/afbcore/views/dashboard.py
index 13cc6dfa..0ca18b71 100644
--- a/afb/afbcore/views/dashboard.py
+++ b/afb/afbcore/views/dashboard.py
@@ -1,4 +1,3 @@
-
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import Http404
from django.shortcuts import render
@@ -28,16 +27,16 @@ def get(self, request):
class ClientDashboardView(LoginRequiredMixin, TemplateView):
def get(self, request):
# Add client-specific dashboard logic here
- return render(request, 'dashboard/client.html')
+ return render(request, "dashboard/client.html")
class ManagerDashboardView(LoginRequiredMixin, TemplateView):
def get(self, request):
# Add manager-specific dashboard logic here
- return render(request, 'dashboard/manager.html')
+ return render(request, "dashboard/manager.html")
class VolunteerDashboardView(LoginRequiredMixin, TemplateView):
def get(self, request):
# Add volunteer-specific dashboard logic here
- return render(request, 'dashboard/volunteer.html')
+ return render(request, "dashboard/volunteer.html")
diff --git a/afb/manage.py b/afb/manage.py
index bc895c46..157be528 100755
--- a/afb/manage.py
+++ b/afb/manage.py
@@ -6,7 +6,7 @@
def main():
"""Run administrative tasks."""
- os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'afb.settings')
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "afb.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
@@ -18,5 +18,5 @@ def main():
execute_from_command_line(sys.argv)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/afb/theme/apps.py b/afb/theme/apps.py
index bec74645..dd24136d 100644
--- a/afb/theme/apps.py
+++ b/afb/theme/apps.py
@@ -2,4 +2,4 @@
class ThemeConfig(AppConfig):
- name = 'theme'
+ name = "theme"