codex-django-cli 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codex_django_cli/__init__.py +12 -0
- codex_django_cli/blueprints/apps/default/__init__.py +0 -0
- codex_django_cli/blueprints/apps/default/admin/__init__.py +0 -0
- codex_django_cli/blueprints/apps/default/apps.py.j2 +0 -0
- codex_django_cli/blueprints/apps/default/forms/__init__.py +0 -0
- codex_django_cli/blueprints/apps/default/models/__init__.py +0 -0
- codex_django_cli/blueprints/apps/default/modules/__init__.py +0 -0
- codex_django_cli/blueprints/apps/default/selector/__init__.py +0 -0
- codex_django_cli/blueprints/apps/default/services/__init__.py +0 -0
- codex_django_cli/blueprints/apps/default/tests/__init__.py +0 -0
- codex_django_cli/blueprints/apps/default/translations.py.j2 +0 -0
- codex_django_cli/blueprints/apps/default/urls.py.j2 +0 -0
- codex_django_cli/blueprints/apps/default/views/__init__.py +0 -0
- codex_django_cli/blueprints/deploy/shared/.dockerignore.j2 +24 -0
- codex_django_cli/blueprints/deploy/shared/.env.example.j2 +64 -0
- codex_django_cli/blueprints/deploy/shared/backend/Dockerfile.j2 +36 -0
- codex_django_cli/blueprints/deploy/shared/backend/entrypoint.sh.j2 +20 -0
- codex_django_cli/blueprints/deploy/shared/nginx/Dockerfile.local.j2 +14 -0
- codex_django_cli/blueprints/deploy/shared/nginx/nginx-main.conf.j2 +67 -0
- codex_django_cli/blueprints/deploy/shared/nginx/site-local.conf.j2 +66 -0
- codex_django_cli/blueprints/deploy/shared/worker/Dockerfile.j2 +25 -0
- codex_django_cli/blueprints/deploy/stack/docker/base.Dockerfile.j2 +38 -0
- codex_django_cli/blueprints/deploy/stack/docker/django.Dockerfile.j2 +27 -0
- codex_django_cli/blueprints/deploy/stack/docker/entrypoint.sh.j2 +19 -0
- codex_django_cli/blueprints/deploy/stack/docker-compose.apps.yml.j2 +41 -0
- codex_django_cli/blueprints/deploy/stack/docker-compose.infra.yml.j2 +80 -0
- codex_django_cli/blueprints/deploy/stack/docker-compose.local.apps.yml.j2 +41 -0
- codex_django_cli/blueprints/deploy/stack/docker-compose.local.infra.yml.j2 +94 -0
- codex_django_cli/blueprints/deploy/stack/docker-compose.test.yml.j2 +63 -0
- codex_django_cli/blueprints/deploy/stack/nginx/Dockerfile.j2 +12 -0
- codex_django_cli/blueprints/deploy/stack/nginx/conf.d/default.conf.j2 +68 -0
- codex_django_cli/blueprints/deploy/stack/nginx/site.conf.template.j2 +81 -0
- codex_django_cli/blueprints/deploy/stack_workflows/ci-develop.yml.j2 +42 -0
- codex_django_cli/blueprints/deploy/stack_workflows/ci-main.yml.j2 +165 -0
- codex_django_cli/blueprints/deploy/stack_workflows/deploy-cluster.yml.j2 +112 -0
- codex_django_cli/blueprints/deploy/standalone/docker-compose.prod.yml.j2 +118 -0
- codex_django_cli/blueprints/deploy/standalone/docker-compose.test.yml.j2 +86 -0
- codex_django_cli/blueprints/deploy/standalone/docker-compose.yml.j2 +151 -0
- codex_django_cli/blueprints/deploy/standalone/nginx/Dockerfile.j2 +18 -0
- codex_django_cli/blueprints/deploy/standalone/nginx/site.conf.template.j2 +168 -0
- codex_django_cli/blueprints/deploy/standalone_workflows/ci-develop.yml.j2 +42 -0
- codex_django_cli/blueprints/deploy/standalone_workflows/ci-main.yml.j2 +113 -0
- codex_django_cli/blueprints/deploy/standalone_workflows/deploy-production-tag.yml.j2 +211 -0
- codex_django_cli/blueprints/features/booking/booking/__init__.py.j2 +0 -0
- codex_django_cli/blueprints/features/booking/booking/admin.py.j2 +52 -0
- codex_django_cli/blueprints/features/booking/booking/apps.py.j2 +8 -0
- codex_django_cli/blueprints/features/booking/booking/models.py.j2 +142 -0
- codex_django_cli/blueprints/features/booking/booking/selectors.py.j2 +102 -0
- codex_django_cli/blueprints/features/booking/booking/urls.py.j2 +12 -0
- codex_django_cli/blueprints/features/booking/booking/views.py.j2 +174 -0
- codex_django_cli/blueprints/features/booking/booking/wiki.md.j2 +142 -0
- codex_django_cli/blueprints/features/booking/cabinet/templates/cabinet/booking/my_bookings.html +249 -0
- codex_django_cli/blueprints/features/booking/cabinet/views/booking.py.j2 +70 -0
- codex_django_cli/blueprints/features/booking/system/admin/booking_settings.py.j2 +31 -0
- codex_django_cli/blueprints/features/booking/system/models/booking_settings.py.j2 +7 -0
- codex_django_cli/blueprints/features/booking/templates/booking/booking_page.html +137 -0
- codex_django_cli/blueprints/features/booking/templates/booking/partials/step_confirm.html +143 -0
- codex_django_cli/blueprints/features/booking/templates/booking/partials/step_date.html +184 -0
- codex_django_cli/blueprints/features/booking/templates/booking/partials/step_service.html +78 -0
- codex_django_cli/blueprints/features/booking/templates/booking/partials/step_time.html +89 -0
- codex_django_cli/blueprints/features/client_cabinet/cabinet/adapters.py.j2 +21 -0
- codex_django_cli/blueprints/features/client_cabinet/cabinet/templates/cabinet/client/my_appointments.html +58 -0
- codex_django_cli/blueprints/features/client_cabinet/cabinet/templates/cabinet/client/profile.html +107 -0
- codex_django_cli/blueprints/features/client_cabinet/cabinet/templates/cabinet/client/settings.html +106 -0
- codex_django_cli/blueprints/features/client_cabinet/cabinet/templates/cabinet/client/settings_notifications.html +106 -0
- codex_django_cli/blueprints/features/client_cabinet/cabinet/templates/cabinet/client/settings_privacy.html +135 -0
- codex_django_cli/blueprints/features/client_cabinet/cabinet/views/client.py.j2 +49 -0
- codex_django_cli/blueprints/features/client_cabinet/system/models/user_profile.py.j2 +22 -0
- codex_django_cli/blueprints/features/notifications/arq/client.j2 +22 -0
- codex_django_cli/blueprints/features/notifications/feature/models/email_content.j2 +15 -0
- codex_django_cli/blueprints/features/notifications/feature/selectors/email_content.j2 +23 -0
- codex_django_cli/blueprints/features/notifications/feature/services/notification.j2 +66 -0
- codex_django_cli/blueprints/project/cabinet/__init__.py +0 -0
- codex_django_cli/blueprints/project/cabinet/admin/__init__.py +0 -0
- codex_django_cli/blueprints/project/cabinet/apps.py.j2 +11 -0
- codex_django_cli/blueprints/project/cabinet/cabinet.py.j2 +33 -0
- codex_django_cli/blueprints/project/cabinet/forms/__init__.py +0 -0
- codex_django_cli/blueprints/project/cabinet/mock.py.j2 +110 -0
- codex_django_cli/blueprints/project/cabinet/models/__init__.py +0 -0
- codex_django_cli/blueprints/project/cabinet/modules/__init__.py +0 -0
- codex_django_cli/blueprints/project/cabinet/selector/__init__.py +3 -0
- codex_django_cli/blueprints/project/cabinet/selector/users.py.j2 +25 -0
- codex_django_cli/blueprints/project/cabinet/services/__init__.py +0 -0
- codex_django_cli/blueprints/project/cabinet/static/cabinet/css/base.css +11 -0
- codex_django_cli/blueprints/project/cabinet/static/cabinet/css/compiler_config.json +5 -0
- codex_django_cli/blueprints/project/cabinet/static/cabinet/css/theme/tokens.css +30 -0
- codex_django_cli/blueprints/project/cabinet/static/cabinet/js/app/cabinet.js +37 -0
- codex_django_cli/blueprints/project/cabinet/static/cabinet/js/compiler_config.json +7 -0
- codex_django_cli/blueprints/project/cabinet/templates/cabinet/users/detail.html +91 -0
- codex_django_cli/blueprints/project/cabinet/templates/cabinet/users/index.html +97 -0
- codex_django_cli/blueprints/project/cabinet/tests/__init__.py +0 -0
- codex_django_cli/blueprints/project/cabinet/translations.py.j2 +2 -0
- codex_django_cli/blueprints/project/cabinet/urls.py.j2 +22 -0
- codex_django_cli/blueprints/project/cabinet/views/__init__.py +3 -0
- codex_django_cli/blueprints/project/cabinet/views/users.py.j2 +17 -0
- codex_django_cli/blueprints/project/core/__init__.py.j2 +1 -0
- codex_django_cli/blueprints/project/core/apps.py.j2 +15 -0
- codex_django_cli/blueprints/project/core/asgi.py.j2 +7 -0
- codex_django_cli/blueprints/project/core/logger.py.j2 +57 -0
- codex_django_cli/blueprints/project/core/redis.py.j2 +4 -0
- codex_django_cli/blueprints/project/core/settings/__init__.py.j2 +4 -0
- codex_django_cli/blueprints/project/core/settings/base.py.j2 +67 -0
- codex_django_cli/blueprints/project/core/settings/dev.py.j2 +56 -0
- codex_django_cli/blueprints/project/core/settings/modules/__init__.py.j2 +1 -0
- codex_django_cli/blueprints/project/core/settings/modules/admin.py.j2 +72 -0
- codex_django_cli/blueprints/project/core/settings/modules/apps.py.j2 +64 -0
- codex_django_cli/blueprints/project/core/settings/modules/cache.py.j2 +49 -0
- codex_django_cli/blueprints/project/core/settings/modules/codex.py.j2 +39 -0
- codex_django_cli/blueprints/project/core/settings/modules/database.py.j2 +49 -0
- codex_django_cli/blueprints/project/core/settings/modules/internationalization.py.j2 +43 -0
- codex_django_cli/blueprints/project/core/settings/modules/logging.py.j2 +45 -0
- codex_django_cli/blueprints/project/core/settings/modules/middleware.py.j2 +17 -0
- codex_django_cli/blueprints/project/core/settings/modules/security.py.j2 +53 -0
- codex_django_cli/blueprints/project/core/settings/modules/sitemap.py.j2 +14 -0
- codex_django_cli/blueprints/project/core/settings/modules/static.py.j2 +36 -0
- codex_django_cli/blueprints/project/core/settings/modules/templates.py.j2 +29 -0
- codex_django_cli/blueprints/project/core/settings/prod.py.j2 +77 -0
- codex_django_cli/blueprints/project/core/settings/test.py.j2 +40 -0
- codex_django_cli/blueprints/project/core/sitemaps.py.j2 +26 -0
- codex_django_cli/blueprints/project/core/urls.py.j2 +71 -0
- codex_django_cli/blueprints/project/core/wsgi.py.j2 +7 -0
- codex_django_cli/blueprints/project/features/__init__.py.j2 +0 -0
- codex_django_cli/blueprints/project/features/main/admin/__init__.py +0 -0
- codex_django_cli/blueprints/project/features/main/apps.py.j2 +8 -0
- codex_django_cli/blueprints/project/features/main/forms/__init__.py +0 -0
- codex_django_cli/blueprints/project/features/main/models/__init__.py +0 -0
- codex_django_cli/blueprints/project/features/main/sitemaps.py.j2 +23 -0
- codex_django_cli/blueprints/project/features/main/tests/__init__.py +0 -0
- codex_django_cli/blueprints/project/features/main/translations.py.j2 +2 -0
- codex_django_cli/blueprints/project/features/main/urls.py.j2 +8 -0
- codex_django_cli/blueprints/project/features/main/views/__init__.py.j2 +9 -0
- codex_django_cli/blueprints/project/manage.py.j2 +39 -0
- codex_django_cli/blueprints/project/static/css/base/components.css +88 -0
- codex_django_cli/blueprints/project/static/css/base/footer.css +43 -0
- codex_django_cli/blueprints/project/static/css/base/header.css +76 -0
- codex_django_cli/blueprints/project/static/css/base/layout.css +58 -0
- codex_django_cli/blueprints/project/static/css/base/reset.css +65 -0
- codex_django_cli/blueprints/project/static/css/base/tokens.css +45 -0
- codex_django_cli/blueprints/project/static/css/base.css +31 -0
- codex_django_cli/blueprints/project/static/css/compiler_config.json +10 -0
- codex_django_cli/blueprints/project/static/css/pages/contacts.css +42 -0
- codex_django_cli/blueprints/project/static/css/pages/errors.css +11 -0
- codex_django_cli/blueprints/project/static/css/pages/home.css +120 -0
- codex_django_cli/blueprints/project/static/js/app/main.js +8 -0
- codex_django_cli/blueprints/project/static/js/vendor/alpine.min.js +9 -0
- codex_django_cli/blueprints/project/static/js/vendor/htmx.min.js +9 -0
- codex_django_cli/blueprints/project/static/manifest.json +15 -0
- codex_django_cli/blueprints/project/static/robots.txt +4 -0
- codex_django_cli/blueprints/project/system/__init__.py.j2 +1 -0
- codex_django_cli/blueprints/project/system/admin/__init__.py.j2 +15 -0
- codex_django_cli/blueprints/project/system/admin/seo.py.j2 +28 -0
- codex_django_cli/blueprints/project/system/admin/settings.py.j2 +65 -0
- codex_django_cli/blueprints/project/system/admin/static.py.j2 +18 -0
- codex_django_cli/blueprints/project/system/apps.py.j2 +9 -0
- codex_django_cli/blueprints/project/system/forms/__init__.py.j2 +1 -0
- codex_django_cli/blueprints/project/system/management/__init__.py +0 -0
- codex_django_cli/blueprints/project/system/management/commands/__init__.py +0 -0
- codex_django_cli/blueprints/project/system/management/commands/dev.py.j2 +5 -0
- codex_django_cli/blueprints/project/system/management/commands/menu.py.j2 +81 -0
- codex_django_cli/blueprints/project/system/management/commands/runserver_plus.py.j2 +46 -0
- codex_django_cli/blueprints/project/system/management/commands/update_all_content.py.j2 +17 -0
- codex_django_cli/blueprints/project/system/management/commands/update_site_settings.py.j2 +80 -0
- codex_django_cli/blueprints/project/system/models/__init__.py.j2 +15 -0
- codex_django_cli/blueprints/project/system/models/seo.py.j2 +37 -0
- codex_django_cli/blueprints/project/system/models/settings.py.j2 +31 -0
- codex_django_cli/blueprints/project/system/models/static.py.j2 +13 -0
- codex_django_cli/blueprints/project/system/services/__init__.py.j2 +1 -0
- codex_django_cli/blueprints/project/system/urls.py.j2 +7 -0
- codex_django_cli/blueprints/project/system/views/__init__.py.j2 +1 -0
- codex_django_cli/blueprints/project/system/views/errors.py.j2 +13 -0
- codex_django_cli/blueprints/project/templates/base.html.j2 +53 -0
- codex_django_cli/blueprints/project/templates/errors/400.html +9 -0
- codex_django_cli/blueprints/project/templates/errors/403.html +9 -0
- codex_django_cli/blueprints/project/templates/errors/404.html +16 -0
- codex_django_cli/blueprints/project/templates/errors/500.html +16 -0
- codex_django_cli/blueprints/project/templates/includes/_analytics_body.html +2 -0
- codex_django_cli/blueprints/project/templates/includes/_analytics_head.html +2 -0
- codex_django_cli/blueprints/project/templates/includes/_cookie_consent.html +2 -0
- codex_django_cli/blueprints/project/templates/includes/_critical_css.html +38 -0
- codex_django_cli/blueprints/project/templates/includes/_footer.html +57 -0
- codex_django_cli/blueprints/project/templates/includes/_header.html.j2 +75 -0
- codex_django_cli/blueprints/project/templates/includes/_hreflang_tags.html.j2 +11 -0
- codex_django_cli/blueprints/project/templates/includes/_meta.html +44 -0
- codex_django_cli/blueprints/project/templates/main/contacts.html +38 -0
- codex_django_cli/blueprints/project/templates/main/home.html +128 -0
- codex_django_cli/blueprints/project/templates/main/home.html.j2 +129 -0
- codex_django_cli/blueprints/project/templates/sitemap.xml +16 -0
- codex_django_cli/blueprints/repo/.env.example.j2 +15 -0
- codex_django_cli/blueprints/repo/.github/workflows/.gitkeep +1 -0
- codex_django_cli/blueprints/repo/.gitignore +38 -0
- codex_django_cli/blueprints/repo/README.md.j2 +32 -0
- codex_django_cli/blueprints/repo/docs/README.md +5 -0
- codex_django_cli/blueprints/repo/pyproject.toml.j2 +46 -0
- codex_django_cli/blueprints/repo/tools/dev/check.py.j2 +23 -0
- codex_django_cli/blueprints/repo/tools/dev/generate_project_tree.py +15 -0
- codex_django_cli/commands/__init__.py +1 -0
- codex_django_cli/commands/add_app.py +56 -0
- codex_django_cli/commands/booking.py +92 -0
- codex_django_cli/commands/client_cabinet.py +66 -0
- codex_django_cli/commands/deploy.py +96 -0
- codex_django_cli/commands/init.py +216 -0
- codex_django_cli/commands/notifications.py +59 -0
- codex_django_cli/commands/quality.py +116 -0
- codex_django_cli/engine.py +113 -0
- codex_django_cli/main.py +470 -0
- codex_django_cli/prompts.py +258 -0
- codex_django_cli/py.typed +0 -0
- codex_django_cli/utils.py +25 -0
- codex_django_cli-0.2.0.dist-info/METADATA +66 -0
- codex_django_cli-0.2.0.dist-info/RECORD +212 -0
- codex_django_cli-0.2.0.dist-info/WHEEL +4 -0
- codex_django_cli-0.2.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{% extends "cabinet/base_client.html" %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
|
|
4
|
+
{% block title %}{% trans "My Appointments" %}{% endblock %}
|
|
5
|
+
{% block page_title %}{% trans "My Appointments" %}{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block sidebar_nav %}
|
|
8
|
+
<li>
|
|
9
|
+
<a href="{% url 'cabinet:my_appointments' %}"
|
|
10
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2
|
|
11
|
+
{% if active_section == 'my' %}cab-nav__item--active{% endif %}"
|
|
12
|
+
hx-get="{% url 'cabinet:my_appointments' %}"
|
|
13
|
+
hx-target="#cab-content"
|
|
14
|
+
hx-push-url="true"
|
|
15
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
16
|
+
<span class="bi bi-calendar-check fs-5 flex-shrink-0"></span>
|
|
17
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "My Appointments" %}</span>
|
|
18
|
+
</a>
|
|
19
|
+
</li>
|
|
20
|
+
<li>
|
|
21
|
+
<a href="{% url 'cabinet:profile' %}"
|
|
22
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2
|
|
23
|
+
{% if active_section == 'profile' %}cab-nav__item--active{% endif %}"
|
|
24
|
+
hx-get="{% url 'cabinet:profile' %}"
|
|
25
|
+
hx-target="#cab-content"
|
|
26
|
+
hx-push-url="true"
|
|
27
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
28
|
+
<span class="bi bi-person fs-5 flex-shrink-0"></span>
|
|
29
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Profile" %}</span>
|
|
30
|
+
</a>
|
|
31
|
+
</li>
|
|
32
|
+
{% endblock %}
|
|
33
|
+
|
|
34
|
+
{% block sidebar_settings_link %}
|
|
35
|
+
<a href="{% url 'cabinet:settings' %}"
|
|
36
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 mx-2 rounded"
|
|
37
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
38
|
+
<span class="bi bi-gear fs-5 flex-shrink-0"></span>
|
|
39
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap; font-size: 0.875rem;">{% trans "Settings" %}</span>
|
|
40
|
+
</a>
|
|
41
|
+
{% endblock %}
|
|
42
|
+
|
|
43
|
+
{% block cabinet_content %}
|
|
44
|
+
|
|
45
|
+
{# ─── Empty state (default) ─── #}
|
|
46
|
+
{% block appointments_content %}
|
|
47
|
+
<div class="card border-0 shadow-sm">
|
|
48
|
+
<div class="card-header bg-white border-0 pt-3 pb-0 d-flex align-items-center justify-content-between">
|
|
49
|
+
<h6 class="fw-semibold mb-0">{% trans "Upcoming" %}</h6>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="card-body text-center py-5">
|
|
52
|
+
<span class="bi bi-calendar-x fs-1 text-muted d-block mb-2"></span>
|
|
53
|
+
<p class="text-muted mb-0">{% trans "No upcoming appointments" %}</p>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
{% endblock %}
|
|
57
|
+
|
|
58
|
+
{% endblock %}
|
codex_django_cli/blueprints/features/client_cabinet/cabinet/templates/cabinet/client/profile.html
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{% extends "cabinet/base_client.html" %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
|
|
4
|
+
{% block title %}{% trans "My Profile" %}{% endblock %}
|
|
5
|
+
{% block page_title %}{% trans "My Profile" %}{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block sidebar_nav %}
|
|
8
|
+
<li>
|
|
9
|
+
<a href="{% url 'cabinet:my_appointments' %}"
|
|
10
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2
|
|
11
|
+
{% if active_section == 'my' %}cab-nav__item--active{% endif %}"
|
|
12
|
+
hx-get="{% url 'cabinet:my_appointments' %}"
|
|
13
|
+
hx-target="#cab-content"
|
|
14
|
+
hx-push-url="true"
|
|
15
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
16
|
+
<span class="bi bi-calendar-check fs-5 flex-shrink-0"></span>
|
|
17
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "My Appointments" %}</span>
|
|
18
|
+
</a>
|
|
19
|
+
</li>
|
|
20
|
+
<li>
|
|
21
|
+
<a href="{% url 'cabinet:profile' %}"
|
|
22
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2
|
|
23
|
+
{% if active_section == 'profile' %}cab-nav__item--active{% endif %}"
|
|
24
|
+
hx-get="{% url 'cabinet:profile' %}"
|
|
25
|
+
hx-target="#cab-content"
|
|
26
|
+
hx-push-url="true"
|
|
27
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
28
|
+
<span class="bi bi-person fs-5 flex-shrink-0"></span>
|
|
29
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Profile" %}</span>
|
|
30
|
+
</a>
|
|
31
|
+
</li>
|
|
32
|
+
{% endblock %}
|
|
33
|
+
|
|
34
|
+
{% block sidebar_settings_link %}
|
|
35
|
+
<a href="{% url 'cabinet:settings' %}"
|
|
36
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 mx-2 rounded"
|
|
37
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
38
|
+
<span class="bi bi-gear fs-5 flex-shrink-0"></span>
|
|
39
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap; font-size: 0.875rem;">{% trans "Settings" %}</span>
|
|
40
|
+
</a>
|
|
41
|
+
{% endblock %}
|
|
42
|
+
|
|
43
|
+
{% block cabinet_content %}
|
|
44
|
+
|
|
45
|
+
<div class="row g-4">
|
|
46
|
+
|
|
47
|
+
{# ─── Left col: avatar + quick info ─── #}
|
|
48
|
+
<div class="col-md-4">
|
|
49
|
+
|
|
50
|
+
<div class="card border-0 shadow-sm text-center p-4 mb-3">
|
|
51
|
+
<div class="mx-auto mb-3 rounded-circle d-flex align-items-center justify-content-center fw-bold text-white"
|
|
52
|
+
style="width:80px;height:80px;background:var(--cab-primary);font-size:1.75rem;">
|
|
53
|
+
{{ request.user.first_name|first|upper }}{{ request.user.last_name|first|upper }}
|
|
54
|
+
</div>
|
|
55
|
+
<h6 class="fw-semibold mb-0">{{ request.user.get_full_name|default:request.user.username }}</h6>
|
|
56
|
+
<hr>
|
|
57
|
+
<div class="d-flex justify-content-around text-center">
|
|
58
|
+
{% block profile_stats %}
|
|
59
|
+
<div>
|
|
60
|
+
<div class="fw-bold">—</div>
|
|
61
|
+
<div class="text-muted" style="font-size:.75rem;">{% trans "Visits" %}</div>
|
|
62
|
+
</div>
|
|
63
|
+
{% endblock %}
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
{# ─── Right col: personal data form ─── #}
|
|
70
|
+
<div class="col-md-8">
|
|
71
|
+
|
|
72
|
+
<div class="card border-0 shadow-sm mb-3">
|
|
73
|
+
<div class="card-header bg-white border-0 pt-3 pb-0">
|
|
74
|
+
<h6 class="fw-semibold mb-0">{% trans "Personal Data" %}</h6>
|
|
75
|
+
</div>
|
|
76
|
+
<div class="card-body">
|
|
77
|
+
{% block profile_form %}
|
|
78
|
+
<div class="row g-3">
|
|
79
|
+
<div class="col-md-6">
|
|
80
|
+
<label class="form-label text-muted" style="font-size:.8rem;">{% trans "First name" %}</label>
|
|
81
|
+
<input type="text" class="form-control" value="{{ request.user.first_name }}">
|
|
82
|
+
</div>
|
|
83
|
+
<div class="col-md-6">
|
|
84
|
+
<label class="form-label text-muted" style="font-size:.8rem;">{% trans "Last name" %}</label>
|
|
85
|
+
<input type="text" class="form-control" value="{{ request.user.last_name }}">
|
|
86
|
+
</div>
|
|
87
|
+
<div class="col-md-6">
|
|
88
|
+
<label class="form-label text-muted" style="font-size:.8rem;">{% trans "Phone" %}</label>
|
|
89
|
+
<input type="tel" class="form-control">
|
|
90
|
+
</div>
|
|
91
|
+
<div class="col-md-6">
|
|
92
|
+
<label class="form-label text-muted" style="font-size:.8rem;">{% trans "Email" %}</label>
|
|
93
|
+
<input type="email" class="form-control" value="{{ request.user.email }}" readonly>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="col-12 text-end">
|
|
96
|
+
<button class="btn btn-primary">{% trans "Save" %}</button>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
{% endblock %}
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
{% endblock %}
|
codex_django_cli/blueprints/features/client_cabinet/cabinet/templates/cabinet/client/settings.html
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{% extends "cabinet/base_client.html" %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
|
|
4
|
+
{% block title %}{% trans "Account" %}{% endblock %}
|
|
5
|
+
{% block page_title %}{% trans "Account" %}{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block sidebar_nav %}
|
|
8
|
+
<li>
|
|
9
|
+
<a href="{% url 'cabinet:settings' %}"
|
|
10
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2 cab-nav__item--active"
|
|
11
|
+
hx-get="{% url 'cabinet:settings' %}"
|
|
12
|
+
hx-target="#cab-content"
|
|
13
|
+
hx-push-url="true"
|
|
14
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
15
|
+
<span class="bi bi-shield-lock fs-5 flex-shrink-0"></span>
|
|
16
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Security" %}</span>
|
|
17
|
+
</a>
|
|
18
|
+
</li>
|
|
19
|
+
<li>
|
|
20
|
+
<a href="{% url 'cabinet:settings_notifications' %}"
|
|
21
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2"
|
|
22
|
+
hx-get="{% url 'cabinet:settings_notifications' %}"
|
|
23
|
+
hx-target="#cab-content"
|
|
24
|
+
hx-push-url="true"
|
|
25
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
26
|
+
<span class="bi bi-bell fs-5 flex-shrink-0"></span>
|
|
27
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Notifications" %}</span>
|
|
28
|
+
</a>
|
|
29
|
+
</li>
|
|
30
|
+
<li>
|
|
31
|
+
<a href="{% url 'cabinet:settings_privacy' %}"
|
|
32
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2"
|
|
33
|
+
hx-get="{% url 'cabinet:settings_privacy' %}"
|
|
34
|
+
hx-target="#cab-content"
|
|
35
|
+
hx-push-url="true"
|
|
36
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
37
|
+
<span class="bi bi-eye-slash fs-5 flex-shrink-0"></span>
|
|
38
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Privacy" %}</span>
|
|
39
|
+
</a>
|
|
40
|
+
</li>
|
|
41
|
+
{% endblock %}
|
|
42
|
+
|
|
43
|
+
{% block sidebar_settings_link %}
|
|
44
|
+
<a href="{% url 'cabinet:my_appointments' %}"
|
|
45
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 mx-2 rounded"
|
|
46
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
47
|
+
<span class="bi bi-arrow-left fs-5 flex-shrink-0"></span>
|
|
48
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap; font-size: 0.875rem;">{% trans "Back" %}</span>
|
|
49
|
+
</a>
|
|
50
|
+
{% endblock %}
|
|
51
|
+
|
|
52
|
+
{% block cabinet_content %}
|
|
53
|
+
<div class="row g-4">
|
|
54
|
+
<div class="col-md-7">
|
|
55
|
+
<div class="card border-0 shadow-sm mb-3">
|
|
56
|
+
<div class="card-header bg-white border-0 pt-3 pb-0">
|
|
57
|
+
<h6 class="fw-semibold mb-0">{% trans "Login Credentials" %}</h6>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="card-body">
|
|
60
|
+
<div class="mb-3">
|
|
61
|
+
<div class="text-muted mb-1" style="font-size:.8rem;">{% trans "Email" %}</div>
|
|
62
|
+
<div class="d-flex align-items-center justify-content-between">
|
|
63
|
+
<span style="font-size:.9rem;">{{ request.user.email }}</span>
|
|
64
|
+
<button class="btn btn-sm btn-outline-secondary">{% trans "Change" %}</button>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
<hr>
|
|
68
|
+
<div>
|
|
69
|
+
<div class="text-muted mb-1" style="font-size:.8rem;">{% trans "Password" %}</div>
|
|
70
|
+
<div class="d-flex align-items-center justify-content-between">
|
|
71
|
+
<span style="font-size:.9rem;">••••••••</span>
|
|
72
|
+
<button class="btn btn-sm btn-outline-secondary">{% trans "Change" %}</button>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div class="card border-0 shadow-sm" style="border-left:3px solid #ef4444 !important;">
|
|
79
|
+
<div class="card-header bg-white border-0 pt-3 pb-0">
|
|
80
|
+
<h6 class="fw-semibold mb-0 text-danger">{% trans "Danger Zone" %}</h6>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="card-body d-flex flex-column gap-3">
|
|
83
|
+
<div class="d-flex align-items-center justify-content-between">
|
|
84
|
+
<div>
|
|
85
|
+
<div style="font-size:.9rem;">{% trans "Deactivate account" %}</div>
|
|
86
|
+
<div class="text-muted" style="font-size:.8rem;">
|
|
87
|
+
{% trans "Login will be blocked, notifications disabled. History is preserved." %}
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
<button class="btn btn-sm btn-outline-danger ms-3" style="white-space:nowrap;">{% trans "Deactivate" %}</button>
|
|
91
|
+
</div>
|
|
92
|
+
<hr class="my-0">
|
|
93
|
+
<div class="d-flex align-items-center justify-content-between">
|
|
94
|
+
<div>
|
|
95
|
+
<div style="font-size:.9rem;">{% trans "Request data deletion" %}</div>
|
|
96
|
+
<div class="text-muted" style="font-size:.8rem;">
|
|
97
|
+
{% trans "Will be processed within 30 days. Personal data removed, anonymous stats kept." %}
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
<button class="btn btn-sm btn-outline-secondary ms-3" style="white-space:nowrap;">{% trans "Submit request" %}</button>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
{% endblock %}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{% extends "cabinet/base_client.html" %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
|
|
4
|
+
{% block title %}{% trans "Notifications" %}{% endblock %}
|
|
5
|
+
{% block page_title %}{% trans "Account" %}{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block sidebar_nav %}
|
|
8
|
+
<li>
|
|
9
|
+
<a href="{% url 'cabinet:settings' %}"
|
|
10
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2"
|
|
11
|
+
hx-get="{% url 'cabinet:settings' %}" hx-target="#cab-content" hx-push-url="true"
|
|
12
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
13
|
+
<span class="bi bi-shield-lock fs-5 flex-shrink-0"></span>
|
|
14
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Security" %}</span>
|
|
15
|
+
</a>
|
|
16
|
+
</li>
|
|
17
|
+
<li>
|
|
18
|
+
<a href="{% url 'cabinet:settings_notifications' %}"
|
|
19
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2 cab-nav__item--active"
|
|
20
|
+
hx-get="{% url 'cabinet:settings_notifications' %}" hx-target="#cab-content" hx-push-url="true"
|
|
21
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
22
|
+
<span class="bi bi-bell fs-5 flex-shrink-0"></span>
|
|
23
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Notifications" %}</span>
|
|
24
|
+
</a>
|
|
25
|
+
</li>
|
|
26
|
+
<li>
|
|
27
|
+
<a href="{% url 'cabinet:settings_privacy' %}"
|
|
28
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2"
|
|
29
|
+
hx-get="{% url 'cabinet:settings_privacy' %}" hx-target="#cab-content" hx-push-url="true"
|
|
30
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
31
|
+
<span class="bi bi-eye-slash fs-5 flex-shrink-0"></span>
|
|
32
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Privacy" %}</span>
|
|
33
|
+
</a>
|
|
34
|
+
</li>
|
|
35
|
+
{% endblock %}
|
|
36
|
+
|
|
37
|
+
{% block sidebar_settings_link %}
|
|
38
|
+
<a href="{% url 'cabinet:my_appointments' %}"
|
|
39
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 mx-2 rounded"
|
|
40
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
41
|
+
<span class="bi bi-arrow-left fs-5 flex-shrink-0"></span>
|
|
42
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap; font-size: 0.875rem;">{% trans "Back" %}</span>
|
|
43
|
+
</a>
|
|
44
|
+
{% endblock %}
|
|
45
|
+
|
|
46
|
+
{% block cabinet_content %}
|
|
47
|
+
<div class="row g-4">
|
|
48
|
+
<div class="col-md-7">
|
|
49
|
+
<div class="card border-0 shadow-sm">
|
|
50
|
+
<div class="card-header bg-white border-0 pt-3 pb-0">
|
|
51
|
+
<h6 class="fw-semibold mb-0">{% trans "Notifications" %}</h6>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="card-body">
|
|
54
|
+
{% for item in notifications %}
|
|
55
|
+
<div class="d-flex align-items-center justify-content-between py-2 {% if not forloop.last %}border-bottom{% endif %}">
|
|
56
|
+
<div>
|
|
57
|
+
<div style="font-size:.9rem;">{{ item.title }}</div>
|
|
58
|
+
<div class="text-muted" style="font-size:.8rem;">{{ item.description }}</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="form-check form-switch mb-0">
|
|
61
|
+
<input class="form-check-input" type="checkbox" {% if item.enabled %}checked{% endif %} style="width:2.5rem;height:1.25rem;">
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
{% empty %}
|
|
65
|
+
<div class="d-flex align-items-center justify-content-between py-2 border-bottom">
|
|
66
|
+
<div>
|
|
67
|
+
<div style="font-size:.9rem;">{% trans "Appointment reminder" %}</div>
|
|
68
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "24 hours before visit" %}</div>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="form-check form-switch mb-0">
|
|
71
|
+
<input class="form-check-input" type="checkbox" checked style="width:2.5rem;height:1.25rem;">
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="d-flex align-items-center justify-content-between py-2 border-bottom">
|
|
75
|
+
<div>
|
|
76
|
+
<div style="font-size:.9rem;">{% trans "SMS notifications" %}</div>
|
|
77
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "Booking status via SMS" %}</div>
|
|
78
|
+
</div>
|
|
79
|
+
<div class="form-check form-switch mb-0">
|
|
80
|
+
<input class="form-check-input" type="checkbox" checked style="width:2.5rem;height:1.25rem;">
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="d-flex align-items-center justify-content-between py-2 border-bottom">
|
|
84
|
+
<div>
|
|
85
|
+
<div style="font-size:.9rem;">{% trans "Email newsletter" %}</div>
|
|
86
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "Promotions, news, and special offers" %}</div>
|
|
87
|
+
</div>
|
|
88
|
+
<div class="form-check form-switch mb-0">
|
|
89
|
+
<input class="form-check-input" type="checkbox" style="width:2.5rem;height:1.25rem;">
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
<div class="d-flex align-items-center justify-content-between py-2">
|
|
93
|
+
<div>
|
|
94
|
+
<div style="font-size:.9rem;">{% trans "Push notifications" %}</div>
|
|
95
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "In browser or app" %}</div>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="form-check form-switch mb-0">
|
|
98
|
+
<input class="form-check-input" type="checkbox" style="width:2.5rem;height:1.25rem;">
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
{% endfor %}
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
{% endblock %}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
{% extends "cabinet/base_client.html" %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
|
|
4
|
+
{% block title %}{% trans "Privacy" %}{% endblock %}
|
|
5
|
+
{% block page_title %}{% trans "Account" %}{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block sidebar_nav %}
|
|
8
|
+
<li>
|
|
9
|
+
<a href="{% url 'cabinet:settings' %}"
|
|
10
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2"
|
|
11
|
+
hx-get="{% url 'cabinet:settings' %}" hx-target="#cab-content" hx-push-url="true"
|
|
12
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
13
|
+
<span class="bi bi-shield-lock fs-5 flex-shrink-0"></span>
|
|
14
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Security" %}</span>
|
|
15
|
+
</a>
|
|
16
|
+
</li>
|
|
17
|
+
<li>
|
|
18
|
+
<a href="{% url 'cabinet:settings_notifications' %}"
|
|
19
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2"
|
|
20
|
+
hx-get="{% url 'cabinet:settings_notifications' %}" hx-target="#cab-content" hx-push-url="true"
|
|
21
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
22
|
+
<span class="bi bi-bell fs-5 flex-shrink-0"></span>
|
|
23
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Notifications" %}</span>
|
|
24
|
+
</a>
|
|
25
|
+
</li>
|
|
26
|
+
<li>
|
|
27
|
+
<a href="{% url 'cabinet:settings_privacy' %}"
|
|
28
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 rounded mx-2 cab-nav__item--active"
|
|
29
|
+
hx-get="{% url 'cabinet:settings_privacy' %}" hx-target="#cab-content" hx-push-url="true"
|
|
30
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
31
|
+
<span class="bi bi-eye-slash fs-5 flex-shrink-0"></span>
|
|
32
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap;">{% trans "Privacy" %}</span>
|
|
33
|
+
</a>
|
|
34
|
+
</li>
|
|
35
|
+
{% endblock %}
|
|
36
|
+
|
|
37
|
+
{% block sidebar_settings_link %}
|
|
38
|
+
<a href="{% url 'cabinet:my_appointments' %}"
|
|
39
|
+
class="cab-nav__item d-flex align-items-center px-3 py-2 mx-2 rounded"
|
|
40
|
+
style="color: var(--cab-sidebar-text); transition: background 0.15s;">
|
|
41
|
+
<span class="bi bi-arrow-left fs-5 flex-shrink-0"></span>
|
|
42
|
+
<span class="cab-nav__label ms-3" style="white-space: nowrap; font-size: 0.875rem;">{% trans "Back" %}</span>
|
|
43
|
+
</a>
|
|
44
|
+
{% endblock %}
|
|
45
|
+
|
|
46
|
+
{% block cabinet_content %}
|
|
47
|
+
<div class="row g-4">
|
|
48
|
+
<div class="col-md-7">
|
|
49
|
+
|
|
50
|
+
<div class="card border-0 shadow-sm mb-3">
|
|
51
|
+
<div class="card-header bg-white border-0 pt-3 pb-0">
|
|
52
|
+
<h6 class="fw-semibold mb-0">{% trans "Profile Visibility" %}</h6>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="card-body">
|
|
55
|
+
<div class="d-flex align-items-center justify-content-between py-2 border-bottom">
|
|
56
|
+
<div>
|
|
57
|
+
<div style="font-size:.9rem;">{% trans "Show profile photo" %}</div>
|
|
58
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "Other users will see your avatar" %}</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="form-check form-switch mb-0">
|
|
61
|
+
<input class="form-check-input" type="checkbox" checked style="width:2.5rem;height:1.25rem;">
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="d-flex align-items-center justify-content-between py-2 border-bottom">
|
|
65
|
+
<div>
|
|
66
|
+
<div style="font-size:.9rem;">{% trans "Show birth date" %}</div>
|
|
67
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "Month and day only, no year" %}</div>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="form-check form-switch mb-0">
|
|
70
|
+
<input class="form-check-input" type="checkbox" style="width:2.5rem;height:1.25rem;">
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
<div class="d-flex align-items-center justify-content-between py-2">
|
|
74
|
+
<div>
|
|
75
|
+
<div style="font-size:.9rem;">{% trans "Show visit history" %}</div>
|
|
76
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "Staff can see previous bookings" %}</div>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="form-check form-switch mb-0">
|
|
79
|
+
<input class="form-check-input" type="checkbox" checked style="width:2.5rem;height:1.25rem;">
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<div class="card border-0 shadow-sm mb-3">
|
|
86
|
+
<div class="card-header bg-white border-0 pt-3 pb-0">
|
|
87
|
+
<h6 class="fw-semibold mb-0">{% trans "Data & Personalization" %}</h6>
|
|
88
|
+
</div>
|
|
89
|
+
<div class="card-body">
|
|
90
|
+
<div class="d-flex align-items-center justify-content-between py-2 border-bottom">
|
|
91
|
+
<div>
|
|
92
|
+
<div style="font-size:.9rem;">{% trans "Personal recommendations" %}</div>
|
|
93
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "Use history for service suggestions" %}</div>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="form-check form-switch mb-0">
|
|
96
|
+
<input class="form-check-input" type="checkbox" checked style="width:2.5rem;height:1.25rem;">
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="d-flex align-items-center justify-content-between py-2">
|
|
100
|
+
<div>
|
|
101
|
+
<div style="font-size:.9rem;">{% trans "Usage analytics" %}</div>
|
|
102
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "Helps improve the service" %}</div>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="form-check form-switch mb-0">
|
|
105
|
+
<input class="form-check-input" type="checkbox" checked style="width:2.5rem;height:1.25rem;">
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="card border-0 shadow-sm">
|
|
112
|
+
<div class="card-header bg-white border-0 pt-3 pb-0">
|
|
113
|
+
<h6 class="fw-semibold mb-0">{% trans "Your Data" %}</h6>
|
|
114
|
+
</div>
|
|
115
|
+
<div class="card-body">
|
|
116
|
+
<div class="d-flex align-items-center justify-content-between py-2 border-bottom">
|
|
117
|
+
<div>
|
|
118
|
+
<div style="font-size:.9rem;">{% trans "Download my data" %}</div>
|
|
119
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "Export all account information" %}</div>
|
|
120
|
+
</div>
|
|
121
|
+
<button class="btn btn-sm btn-outline-secondary">{% trans "Request" %}</button>
|
|
122
|
+
</div>
|
|
123
|
+
<div class="d-flex align-items-center justify-content-between py-2">
|
|
124
|
+
<div>
|
|
125
|
+
<div style="font-size:.9rem;">{% trans "Clear browsing history" %}</div>
|
|
126
|
+
<div class="text-muted" style="font-size:.8rem;">{% trans "Remove recently viewed services" %}</div>
|
|
127
|
+
</div>
|
|
128
|
+
<button class="btn btn-sm btn-outline-secondary">{% trans "Clear" %}</button>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
{% endblock %}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Client-facing views for the personal area (/cabinet/my/).
|
|
3
|
+
|
|
4
|
+
All views require login. Override or extend as needed.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from django.contrib.auth.decorators import login_required
|
|
8
|
+
from django.shortcuts import render
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@login_required
|
|
12
|
+
def profile_view(request):
|
|
13
|
+
"""User profile page."""
|
|
14
|
+
return render(request, "cabinet/client/profile.html", {
|
|
15
|
+
"active_section": "profile",
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@login_required
|
|
20
|
+
def my_appointments_view(request):
|
|
21
|
+
"""My appointments / bookings list."""
|
|
22
|
+
return render(request, "cabinet/client/my_appointments.html", {
|
|
23
|
+
"active_section": "my",
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@login_required
|
|
28
|
+
def settings_view(request):
|
|
29
|
+
"""Account security settings."""
|
|
30
|
+
return render(request, "cabinet/client/settings.html", {
|
|
31
|
+
"active_section": "settings",
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@login_required
|
|
36
|
+
def settings_notifications_view(request):
|
|
37
|
+
"""Notification preferences."""
|
|
38
|
+
return render(request, "cabinet/client/settings_notifications.html", {
|
|
39
|
+
"active_section": "settings",
|
|
40
|
+
"notifications": [], # populate from your notification model
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@login_required
|
|
45
|
+
def settings_privacy_view(request):
|
|
46
|
+
"""Privacy settings."""
|
|
47
|
+
return render(request, "cabinet/client/settings_privacy.html", {
|
|
48
|
+
"active_section": "settings",
|
|
49
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
|
|
3
|
+
from codex_django.system.mixins import AbstractUserProfile
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class UserProfile(AbstractUserProfile):
|
|
7
|
+
"""
|
|
8
|
+
Project-level user profile.
|
|
9
|
+
|
|
10
|
+
Extend this model with project-specific fields as needed.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
# Add custom fields below, e.g.:
|
|
14
|
+
# preferred_language = models.CharField(max_length=10, blank=True)
|
|
15
|
+
|
|
16
|
+
class Meta:
|
|
17
|
+
verbose_name = "Профиль пользователя"
|
|
18
|
+
verbose_name_plural = "Профили пользователей"
|
|
19
|
+
ordering = ["-created_at"]
|
|
20
|
+
|
|
21
|
+
def __str__(self) -> str:
|
|
22
|
+
return self.get_full_name() or f"Profile #{self.pk}"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DjangoArqClient singleton for this project.
|
|
3
|
+
|
|
4
|
+
Import ``arq_client`` wherever you need to enqueue ARQ jobs directly.
|
|
5
|
+
Prefer using DjangoQueueAdapter (via NotificationService) for notifications.
|
|
6
|
+
|
|
7
|
+
Usage::
|
|
8
|
+
|
|
9
|
+
# Sync (WSGI view / management command):
|
|
10
|
+
from core.arq.client import arq_client
|
|
11
|
+
job_id = arq_client.enqueue("my_task", payload=data)
|
|
12
|
+
|
|
13
|
+
# Async (ASGI view):
|
|
14
|
+
from core.arq.client import arq_client
|
|
15
|
+
job_id = await arq_client.aenqueue("my_task", payload=data)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from codex_django.notifications import DjangoArqClient
|
|
19
|
+
|
|
20
|
+
# By default reads ARQ_REDIS_URL (or REDIS_URL) from Django settings.
|
|
21
|
+
# Projects can also build and inject a ready adapter/pool explicitly.
|
|
22
|
+
arq_client = DjangoArqClient()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from codex_django.notifications import BaseEmailContentMixin
|
|
2
|
+
from django.db import models
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class EmailContent(BaseEmailContentMixin):
|
|
6
|
+
"""
|
|
7
|
+
Stores notification content blocks for {{ app_name }}.
|
|
8
|
+
|
|
9
|
+
Each row is a reusable text fragment (subject, body snippet, etc.)
|
|
10
|
+
identified by a unique ``key`` and retrieved by the notification selector.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
class Meta(BaseEmailContentMixin.Meta):
|
|
14
|
+
verbose_name = "Email Content"
|
|
15
|
+
verbose_name_plural = "Email Contents"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
EmailContent selector singleton for {{ app_name }}.
|
|
3
|
+
|
|
4
|
+
Wires together the three adapters and the EmailContent model.
|
|
5
|
+
Import ``selector`` where you need to look up notification content.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from codex_django.notifications import (
|
|
9
|
+
BaseEmailContentSelector,
|
|
10
|
+
DjangoCacheAdapter,
|
|
11
|
+
DjangoI18nAdapter,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from ..models.email_content import EmailContent
|
|
15
|
+
|
|
16
|
+
cache_adapter = DjangoCacheAdapter()
|
|
17
|
+
i18n_adapter = DjangoI18nAdapter()
|
|
18
|
+
|
|
19
|
+
selector = BaseEmailContentSelector(
|
|
20
|
+
model=EmailContent,
|
|
21
|
+
cache_adapter=cache_adapter,
|
|
22
|
+
i18n_adapter=i18n_adapter,
|
|
23
|
+
)
|