sandwitches 2.5.2__tar.gz → 2.5.4__tar.gz

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.
Files changed (88) hide show
  1. {sandwitches-2.5.2 → sandwitches-2.5.4}/PKG-INFO +1 -1
  2. {sandwitches-2.5.2 → sandwitches-2.5.4}/pyproject.toml +1 -1
  3. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/admin_base.html +24 -21
  4. sandwitches-2.5.4/src/sandwitches/templates/admin/partials/order_rows.html +41 -0
  5. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/recipe_list.html +1 -9
  6. sandwitches-2.5.4/src/sandwitches/templates/admin/settings.html +41 -0
  7. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/cart.html +15 -16
  8. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/ingredients_section.html +1 -1
  9. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/navbar.html +3 -3
  10. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/rating_section.html +1 -0
  11. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/recipe_header.html +1 -1
  12. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/side_menu.html +0 -4
  13. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/detail.html +22 -30
  14. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/index.html +2 -3
  15. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/partials/recipe_list.html +25 -20
  16. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/profile.html +18 -18
  17. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/urls.py +6 -0
  18. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/utils.py +3 -0
  19. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/views.py +59 -3
  20. sandwitches-2.5.2/src/sandwitches/templates/admin/partials/order_rows.html +0 -28
  21. {sandwitches-2.5.2 → sandwitches-2.5.4}/README.md +0 -0
  22. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/__init__.py +0 -0
  23. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/admin.py +0 -0
  24. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/api.py +0 -0
  25. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/asgi.py +0 -0
  26. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/feeds.py +0 -0
  27. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/forms.py +0 -0
  28. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/locale/nl/LC_MESSAGES/django.mo +0 -0
  29. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/locale/nl/LC_MESSAGES/django.po +0 -0
  30. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/management/__init__.py +0 -0
  31. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/management/commands/__init__.py +0 -0
  32. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/management/commands/reset_daily_orders.py +0 -0
  33. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0001_initial.py +0 -0
  34. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0002_historicalrecipe_servings_recipe_servings.py +0 -0
  35. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0003_setting.py +0 -0
  36. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0004_alter_setting_ai_api_key_and_more.py +0 -0
  37. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0005_rating_comment.py +0 -0
  38. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0006_historicalrecipe_is_highlighted_and_more.py +0 -0
  39. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0007_historicalrecipe_price_recipe_price_order.py +0 -0
  40. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0008_historicalrecipe_daily_orders_count_and_more.py +0 -0
  41. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0009_historicalrecipe_is_approved_recipe_is_approved.py +0 -0
  42. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0010_rename_is_approved_historicalrecipe_is_community_made_and_more.py +0 -0
  43. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0011_alter_historicalrecipe_is_community_made_and_more.py +0 -0
  44. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0012_rename_is_community_made_historicalrecipe_is_approved_and_more.py +0 -0
  45. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0013_cartitem.py +0 -0
  46. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0014_ensure_groups_exist.py +0 -0
  47. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0015_order_completed_alter_order_status_and_more.py +0 -0
  48. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0016_user_theme.py +0 -0
  49. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/0017_setting_gotify_token_setting_gotify_url.py +0 -0
  50. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/migrations/__init__.py +0 -0
  51. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/models.py +0 -0
  52. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/settings.py +0 -0
  53. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/storage.py +0 -0
  54. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/tasks.py +0 -0
  55. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/confirm_delete.html +0 -0
  56. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/dashboard.html +0 -0
  57. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/order_list.html +0 -0
  58. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/partials/dashboard_charts.html +0 -0
  59. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/rating_list.html +0 -0
  60. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/recipe_approval_list.html +0 -0
  61. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/recipe_form.html +0 -0
  62. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/tag_form.html +0 -0
  63. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/tag_list.html +0 -0
  64. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/task_detail.html +0 -0
  65. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/task_list.html +0 -0
  66. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/user_form.html +0 -0
  67. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/admin/user_list.html +0 -0
  68. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/base.html +0 -0
  69. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/base_beer.html +0 -0
  70. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/community.html +0 -0
  71. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/carousel_scripts.html +0 -0
  72. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/favorites_search_form.html +0 -0
  73. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/footer.html +0 -0
  74. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/ingredients_scripts.html +0 -0
  75. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/instructions_section.html +0 -0
  76. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/search_form.html +0 -0
  77. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/search_scripts.html +0 -0
  78. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/components/user_menu.html +0 -0
  79. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/favorites.html +0 -0
  80. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/login.html +0 -0
  81. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/order_detail.html +0 -0
  82. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/settings.html +0 -0
  83. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/setup.html +0 -0
  84. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templates/signup.html +0 -0
  85. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templatetags/__init__.py +0 -0
  86. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templatetags/custom_filters.py +0 -0
  87. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/templatetags/markdown_extras.py +0 -0
  88. {sandwitches-2.5.2 → sandwitches-2.5.4}/src/sandwitches/wsgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sandwitches
3
- Version: 2.5.2
3
+ Version: 2.5.4
4
4
  Summary: Add your description here
5
5
  Author: Martyn van Dijke
6
6
  Author-email: Martyn van Dijke <martijnvdijke600@gmail.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sandwitches"
3
- version = "2.5.2"
3
+ version = "2.5.4"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -26,8 +26,7 @@
26
26
  <i>menu</i>
27
27
  </button>
28
28
  <a href="{% url 'admin_dashboard' %}" class="row align-center">
29
- <img src="{% static 'icons/icon.svg' %}" class="circle small">
30
- <h6 class="max">{% trans "Sandwitches Admin" %} | {% block admin_title %}{% endblock %}</h6>
29
+ <img src="{% static 'icons/icon.svg' %}" class="circle">
31
30
  </a>
32
31
  <div class="max"></div>
33
32
 
@@ -45,48 +44,52 @@
45
44
  <h5 class="max">{% trans "Admin" %}</h5>
46
45
  </header>
47
46
  <div class="space"></div>
48
- <a href="{% url 'admin_dashboard' %}" class="{% if request.resolver_match.url_name == 'admin_dashboard' %}active{% endif %}">
47
+ <a href="{% url 'admin_dashboard' %}" class="padding {% if request.resolver_match.url_name == 'admin_dashboard' %}active{% endif %}">
49
48
  <i>dashboard</i>
50
- <span>{% trans "Dashboard" %}</span>
49
+ <span class="large-text">{% trans "Dashboard" %}</span>
51
50
  </a>
52
- <a href="{% url 'admin_recipe_list' %}" class="{% if request.resolver_match.url_name == 'admin_recipe_list' %}active{% endif %}">
51
+ <a href="{% url 'admin_recipe_list' %}" class="padding {% if request.resolver_match.url_name == 'admin_recipe_list' %}active{% endif %}">
53
52
  <i>restaurant</i>
54
- <span>{% trans "Recipes" %}</span>
53
+ <span class="large-text">{% trans "Recipes" %}</span>
55
54
  </a>
56
- <a href="{% url 'admin_recipe_approval_list' %}" class="{% if request.resolver_match.url_name == 'admin_recipe_approval_list' %}active{% endif %}">
55
+ <a href="{% url 'admin_recipe_approval_list' %}" class="padding {% if request.resolver_match.url_name == 'admin_recipe_approval_list' %}active{% endif %}">
57
56
  <i>how_to_reg</i>
58
- <span>{% trans "Approvals" %}</span>
57
+ <span class="large-text">{% trans "Approvals" %}</span>
59
58
  </a>
60
- <a href="{% url 'admin_user_list' %}" class="{% if request.resolver_match.url_name == 'admin_user_list' %}active{% endif %}">
59
+ <a href="{% url 'admin_user_list' %}" class="padding {% if request.resolver_match.url_name == 'admin_user_list' %}active{% endif %}">
61
60
  <i>people</i>
62
- <span>{% trans "Users" %}</span>
61
+ <span class="large-text">{% trans "Users" %}</span>
63
62
  </a>
64
- <a href="{% url 'admin_tag_list' %}" class="{% if request.resolver_match.url_name == 'admin_tag_list' %}active{% endif %}">
63
+ <a href="{% url 'admin_tag_list' %}" class="padding {% if request.resolver_match.url_name == 'admin_tag_list' %}active{% endif %}">
65
64
  <i>label</i>
66
- <span>{% trans "Tags" %}</span>
65
+ <span class="large-text">{% trans "Tags" %}</span>
67
66
  </a>
68
- <a href="{% url 'admin_rating_list' %}" class="{% if request.resolver_match.url_name == 'admin_rating_list' %}active{% endif %}">
67
+ <a href="{% url 'admin_rating_list' %}" class="padding {% if request.resolver_match.url_name == 'admin_rating_list' %}active{% endif %}">
69
68
  <i>star</i>
70
- <span>{% trans "Ratings" %}</span>
69
+ <span class="large-text">{% trans "Ratings" %}</span>
71
70
  </a>
72
- <a href="{% url 'admin_order_list' %}" class="{% if request.resolver_match.url_name == 'admin_order_list' %}active{% endif %}">
71
+ <a href="{% url 'admin_order_list' %}" class="padding {% if request.resolver_match.url_name == 'admin_order_list' %}active{% endif %}">
73
72
  <i>shopping_cart</i>
74
- <span>{% trans "Orders" %}</span>
73
+ <span class="large-text">{% trans "Orders" %}</span>
75
74
  </a>
76
- <a href="{% url 'admin_task_list' %}" class="{% if request.resolver_match.url_name == 'admin_task_list' %}active{% endif %}">
75
+ <a href="{% url 'admin_settings' %}" class="padding {% if request.resolver_match.url_name == 'admin_settings' %}active{% endif %}">
76
+ <i>settings</i>
77
+ <span class="large-text">{% trans "Site Settings" %}</span>
78
+ </a>
79
+ <a href="{% url 'admin_task_list' %}" class="padding {% if request.resolver_match.url_name == 'admin_task_list' %}active{% endif %}">
77
80
  <i>assignment</i>
78
- <span>{% trans "Tasks" %}</span>
81
+ <span class="large-text">{% trans "Tasks" %}</span>
79
82
  </a>
80
83
  <div class="divider"></div>
81
- <a href="{% url 'index' %}">
84
+ <a href="{% url 'index' %}" class="padding">
82
85
  <i>home</i>
83
- <span>{% trans "Public Site" %}</span>
86
+ <span class="large-text">{% trans "Public Site" %}</span>
84
87
  </a>
85
88
  </nav>
86
89
  </dialog>
87
90
 
88
91
  {% if user.is_authenticated %}
89
- <menu id="user-menu" class="no-wrap left">
92
+ <menu id="user-menu" class="left">
90
93
  <a href="{% url 'admin:logout' %}" class="row"><i>logout</i>{% trans "Logout" %}</a>
91
94
  </menu>
92
95
  {% endif %}
@@ -0,0 +1,41 @@
1
+ {% load i18n %}
2
+ {% for order in orders %}
3
+ <tr>
4
+ <td>{{ order.id }}</td>
5
+ <td>
6
+ <div class="row align-center">
7
+ {% if order.user.avatar %}
8
+ <img src="{{ order.user.avatar.url }}" class="circle tiny">
9
+ {% else %}
10
+ <i class="circle tiny">person</i>
11
+ {% endif %}
12
+ <span class="max">{{ order.user.username }}</span>
13
+ </div>
14
+ </td>
15
+ <td>{{ order.recipe.title }}</td>
16
+ <td>€ {{ order.total_price }} </td>
17
+ <td>
18
+ <form method="post" action="{% url 'admin_order_update_status' order.pk %}" class="row align-center no-space">
19
+ {% csrf_token %}
20
+ <div class="field border round small no-margin">
21
+ <select name="status" onchange="this.form.submit()" {% if order.status == 'COMPLETED' or order.status == 'CANCELLED' %}disabled{% endif %}>
22
+ {% for val, label in status_choices %}
23
+ <option value="{{ val }}" {% if order.status == val %}selected{% endif %}>{{ label }}</option>
24
+ {% endfor %}
25
+ </select>
26
+ <i>arrow_drop_down</i>
27
+ </div>
28
+ {% if order.status == 'COMPLETED' or order.status == 'CANCELLED' %}
29
+ <span class="chip {% if order.status == 'COMPLETED' %}primary{% else %}error{% endif %} margin">
30
+ {{ order.get_status_display }}
31
+ </span>
32
+ {% endif %}
33
+ </form>
34
+ </td>
35
+ <td>{{ order.created_at|date:"d/m/Y H:i" }}</td>
36
+ </tr>
37
+ {% empty %}
38
+ <tr>
39
+ <td colspan="6" class="center-align">{% trans "No orders found." %}</td>
40
+ </tr>
41
+ {% endfor %}
@@ -38,7 +38,6 @@
38
38
  <th>{% trans "Rating" %}
39
39
  <i class="primary-text">star</i>
40
40
  </th>
41
- <th>{% trans "Approved" %}</th>
42
41
  <th>{% trans "Tags" %}</th>
43
42
  <th>
44
43
  <a href="?sort={% if current_sort == 'uploader' %}-uploader{% else %}uploader{% endif %}" class="row align-center">
@@ -75,7 +74,7 @@
75
74
  </td>
76
75
  <td>
77
76
  {% if recipe.price %}
78
- {{ recipe.price }}
77
+ {{ recipe.price }}
79
78
  {% else %}
80
79
  -
81
80
  {% endif %}
@@ -89,13 +88,6 @@
89
88
  <span>{{ recipe.avg_rating|default:0|floatformat:1 }}</span>
90
89
  </div>
91
90
  </td>
92
- <td class="center-align">
93
- {% if recipe.is_approved %}
94
- <i class="primary-text">check_circle</i>
95
- {% else %}
96
- <i class="primary-text">close</i>
97
- {% endif %}
98
- </td>
99
91
  <td>
100
92
  {% for tag in recipe.tags.all %}
101
93
  <span class="chip tiny">{{ tag.name }}</span>
@@ -0,0 +1,41 @@
1
+ {% extends "admin/admin_base.html" %}
2
+ {% load i18n %}
3
+
4
+ {% block admin_title %}{{ title }}{% endblock %}
5
+
6
+ {% block content %}
7
+ <main class="container">
8
+ <article class="round padding">
9
+ <header>
10
+ <h5 class="max">{% trans "Site Settings" %}</h5>
11
+ </header>
12
+ <div class="space"></div>
13
+ <form method="post">
14
+ {% csrf_token %}
15
+ <div class="grid">
16
+ {% for field in form %}
17
+ <div class="s12 m6">
18
+ <div class="field label border round">
19
+ {{ field }}
20
+ <label>{{ field.label }}</label>
21
+ {% if field.help_text %}
22
+ <div class="helper">{{ field.help_text }}</div>
23
+ {% endif %}
24
+ {% if field.errors %}
25
+ <span class="error">{{ field.errors|striptags }}</span>
26
+ {% endif %}
27
+ </div>
28
+ </div>
29
+ {% endfor %}
30
+ </div>
31
+ <div class="space"></div>
32
+ <nav class="right-align">
33
+ <button type="submit" class="button primary round">
34
+ <i>save</i>
35
+ <span>{% trans "Save Settings" %}</span>
36
+ </button>
37
+ </nav>
38
+ </form>
39
+ </article>
40
+ </main>
41
+ {% endblock %}
@@ -15,31 +15,31 @@
15
15
  {% if cart_items %}
16
16
  <div class="grid">
17
17
  <div class="s12 m8">
18
- <div class="padding border round surface">
19
- <table class="border striped no-space">
18
+ <div class="padding border round secondary-container">
19
+ <table class="border striped large-space">
20
20
  <thead>
21
21
  <tr>
22
- <th class="min">{% trans "Item" %}</th>
23
- <th class="max">{% trans "Description" %}</th>
24
- <th class="min">{% trans "Quantity" %}</th>
25
- <th class="min">{% trans "Price" %}</th>
26
- <th class="min"></th>
22
+ <th>{% trans "Item" %}</th>
23
+ <th>{% trans "Description" %}</th>
24
+ <th>{% trans "Quantity" %}</th>
25
+ <th>{% trans "Price" %}</th>
26
+ <th></th>
27
27
  </tr>
28
28
  </thead>
29
29
  <tbody>
30
30
  {% for item in cart_items %}
31
31
  <tr>
32
- <td class="min">
32
+ <td>
33
33
  {% if item.recipe.image %}
34
- <img src="{{ item.recipe.image_thumbnail.url }}" class="circle small">
34
+ <img src="{{ item.recipe.image_thumbnail.url }}" class="large circle" alt="{{ item.recipe.title }}">
35
35
  {% else %}
36
36
  <i class="circle small gray1">restaurant</i>
37
37
  {% endif %}
38
38
  </td>
39
- <td class="max">
39
+ <td>
40
40
  <a href="{% url 'recipe_detail' item.recipe.slug %}" class="bold">{{ item.recipe.title }}</a>
41
41
  </td>
42
- <td class="min">
42
+ <td>
43
43
  <form action="{% url 'update_cart_quantity' item.pk %}" method="post" class="row no-space align-center">
44
44
  {% csrf_token %}
45
45
  <div class="field border round small no-margin" style="width: 80px;">
@@ -47,8 +47,8 @@
47
47
  </div>
48
48
  </form>
49
49
  </td>
50
- <td class="min no-wrap">{{ item.total_price }} €</td>
51
- <td class="min">
50
+ <td>{{ item.total_price }} €</td>
51
+ <td>
52
52
  <a href="{% url 'remove_from_cart' item.pk %}" class="button circle transparent">
53
53
  <i>delete</i>
54
54
  </a>
@@ -66,7 +66,6 @@
66
66
  <div class="max">{% trans "Subtotal" %}</div>
67
67
  <div class="bold">{{ total }} €</div>
68
68
  </div>
69
- <div class="divider mt-1 mb-1"></div>
70
69
  <div class="row">
71
70
  <div class="max bold">{% trans "Total" %}</div>
72
71
  <div class="bold large-text">{{ total }} €</div>
@@ -74,14 +73,14 @@
74
73
  <div class="space"></div>
75
74
  <form action="{% url 'checkout_cart' %}" method="post">
76
75
  {% csrf_token %}
77
- <button type="submit" class="button primary round extend">
76
+ <button type="submit" class="button primary round">
78
77
  <i>check</i>
79
78
  <span>{% trans "Checkout" %}</span>
80
79
  </button>
81
80
  </form>
82
81
  </article>
83
82
  <div class="space"></div>
84
- <a href="{% url 'index' %}" class="button transparent extend">
83
+ <a href="{% url 'index' %}" class="button secondary round">
85
84
  <i>arrow_back</i>
86
85
  <span>{% trans "Continue Shopping" %}</span>
87
86
  </a>
@@ -6,6 +6,6 @@
6
6
  <input type="number" id="portions" value="{{ recipe.servings }}" min="1" onchange="scaleIngredients()">
7
7
  <button class="button circle transparent" onclick="adjustPortions(1)">+</button>
8
8
  </div>
9
- <div id="ingredients-display" class="card padding flat gray1">
9
+ <div id="ingredients-display" class="card padding">
10
10
  <p class="text-center">{% trans "Loading ingredients..." %}</p>
11
11
  </div>
@@ -12,7 +12,7 @@
12
12
  <a href="{% url 'view_cart' %}" class="button circle transparent">
13
13
  <i>shopping_cart</i>
14
14
  {% if user.cart_items.exists %}
15
- <badge class="red">{{ user.cart_items.count }}</badge>
15
+ <badge class="tertiary round small-padding">{{ user.cart_items.count }}</badge>
16
16
  {% endif %}
17
17
  </a>
18
18
  <a href="{% url 'user_profile' %}">
@@ -22,9 +22,9 @@
22
22
  <img src="https://www.w3schools.com/howto/img_avatar.png" class="circle">
23
23
  {% endif %}
24
24
  </a>
25
- <button class="circle transparent" data-ui="#user-menu">
25
+ <a href="{% url 'user_settings' %}" class="{% if request.resolver_match.url_name == 'user_settings' %}active{% endif %}">
26
26
  <i>more_vert</i>
27
- </button>
27
+ </a>
28
28
  {% else %}
29
29
  <a href="{% url 'login' %}"><button class="chip transparent border white-text">{% trans "Login" %}</button></a>
30
30
  <a href="{% url 'signup' %}"><button class="chip primary">{% trans "Sign up" %}</button></a>
@@ -40,6 +40,7 @@
40
40
  <textarea name="{{ rating_form.comment.name }}" placeholder="{% trans "Add a comment (optional)" %}">{{ user_rating.comment|default:"" }}</textarea>
41
41
  <label>{% trans "Comment" %}</label>
42
42
  </div>
43
+ <div class="space"></div>
43
44
  <button type="submit" class="button primary round mt-2">{% trans "Submit Rating" %}</button>
44
45
  </form>
45
46
  </article>
@@ -3,7 +3,7 @@
3
3
  <h4 class="bold max">{{ recipe.title }}</h4>
4
4
  {% if user.is_authenticated %}
5
5
  <a href="{% url 'toggle_favorite' recipe.pk %}" id="favorite-toggle-button" class="button circle transparent" title="{% trans 'Toggle Favorite' %}">
6
- <i class="{% if recipe in user.favorites.all %}primary-text{% else %}black-text{% endif %}">
6
+ <i class="{% if recipe in user.favorites.all %}red-text{% else %}primary-text{% endif %}">
7
7
  {% if recipe in user.favorites.all %}favorite{% else %}favorite_border{% endif %}
8
8
  </i>
9
9
  </a>
@@ -19,10 +19,6 @@
19
19
  <i class="extra padding">group</i>
20
20
  <span class="large-text">{% trans "Community" %}</span>
21
21
  </a>
22
- <a href="{% url 'user_settings' %}" class="padding {% if request.resolver_match.url_name == 'user_settings' %}active{% endif %}">
23
- <i class="extra padding">settings</i>
24
- <span class="large-text">{% trans "Settings" %}</span>
25
- </a>
26
22
  {% endif %}
27
23
  <a href="/api/docs" class="padding">
28
24
  <i class="extra padding">api</i>
@@ -81,10 +81,9 @@
81
81
 
82
82
  <div class="large-space"></div>
83
83
 
84
- <div class="grid">
85
- <!-- Left Column: Image and Main Info -->
86
- <div class="s12 m12 l5">
87
- <article class="round no-padding elevate">
84
+ <div>
85
+ <aside class="left rounded padding">
86
+ <article class="round no-padding elevate">
88
87
  {% if recipe.image %}
89
88
  <img src="{{ recipe.image_large.url }}"
90
89
  srcset="{{ recipe.image_medium.url }} 700w, {{ recipe.image_large.url }} 1200w"
@@ -127,8 +126,6 @@
127
126
  {% endif %}
128
127
  </div>
129
128
 
130
- <div class="space"></div>
131
- <div class="divider"></div>
132
129
  <div class="space"></div>
133
130
 
134
131
  {% include "components/rating_section.html" %}
@@ -142,31 +139,26 @@
142
139
  {% endif %}
143
140
  </div>
144
141
  </article>
145
- </div>
146
-
147
- <!-- Right Column: Details -->
148
- <div class="s12 m12 l7">
149
- <div class="padding">
150
-
151
- <h5 class="primary-text">{% trans "Description" %}</h5>
152
- <div class="large-text">
153
- {% if recipe.description %}
154
- {{ recipe.description|convert_markdown|safe }}
155
- {% else %}
156
- <p class="italic">{% trans "No description yet." %}</p>
157
- {% endif %}
158
- </div>
159
-
160
- <div class="large-space"></div>
161
-
162
- {% include "components/ingredients_section.html" %}
163
-
164
- <div class="large-space"></div>
165
-
166
- {% include "components/instructions_section.html" %}
167
- </div>
168
- </div>
142
+ </aside>
143
+ <h5>{{ recipe.title }}</h5>
144
+ <div class="large-padding">
145
+ <div class="page active">
146
+ <h5 class="primary-text">{% trans "Description" %}</h5>
147
+ <div class="large-text">
148
+ {% if recipe.description %}
149
+ {{ recipe.description|convert_markdown|safe }}
150
+ {% else %}
151
+ <p class="italic">{% trans "No description yet." %}</p>
152
+ {% endif %}
153
+ </div>
154
+ <div class="small-space"></div>
155
+ {% include "components/ingredients_section.html" %}
156
+ <div class="small-space"></div>
157
+ {% include "components/instructions_section.html" %}
158
+ </div>
159
+ </div>
169
160
  </div>
161
+
170
162
  {% endblock %}
171
163
 
172
164
  {% block extra_scripts %}
@@ -36,10 +36,10 @@
36
36
  <h4 class="upper center-align">{% trans 'Highlights' %}</h4>
37
37
  <div class="small-space"></div>
38
38
  <div class="relative">
39
- <div class="row scroll snap no-scrollbar" id="highlighted-carousel" style="gap: 20px; flex-wrap: nowrap;">
39
+ <div class="row scroll snap no-scrollbar large-padding" id="highlighted-carousel" style="gap: 20px; flex-wrap: nowrap;">
40
40
  {% for recipe in highlighted_recipes %}
41
41
  <a href="{{ recipe.get_absolute_url }}">
42
- <article class="round no-padding elevate" style="min-width: 300px; width: 300px; flex-shrink: 0; scroll-snap-align: start;">
42
+ <article class="round no-padding elevate tertiary-container" style="min-width: 300px; width: 300px; flex-shrink: 0; scroll-snap-align: start;">
43
43
  {% if recipe.image %}
44
44
  <img src="{{ recipe.image_medium.url }}" class="responsive top-round" alt="{{ recipe.title }}" style="height: 200px; object-fit: cover;">
45
45
  {% else %}
@@ -54,7 +54,6 @@
54
54
  </a>
55
55
  {% endfor %}
56
56
  </div>
57
-
58
57
  <button class="circle surface absolute left middle-align elevate" onclick="scrollCarousel(-1)" style="top: 50%; transform: translateY(-50%); left: -20px; z-index: 10;">
59
58
  <i>chevron_left</i>
60
59
  </button>
@@ -2,7 +2,7 @@
2
2
  <div class="grid justify-center" id="recipe-grid">
3
3
  {% for recipe in recipes %}
4
4
  <div class="s12 m6 l4 xl3 recipe-card">
5
- <article class="round no-padding elevate">
5
+ <article class="round no-padding elevate secondary-container">
6
6
  <div style="position: relative;">
7
7
  {% if recipe.image %}
8
8
  <img src="{{ recipe.image_medium.url }}" class="responsive top-round" style="height:220px; width:100%; object-fit:cover; cursor:pointer;" loading="lazy" alt="{{ recipe.title }}" onclick="location.href='{% url 'recipe_detail' recipe.slug %}';">
@@ -14,18 +14,27 @@
14
14
 
15
15
  {% if user.is_authenticated %}
16
16
  <div class="absolute top left padding">
17
- <a href="{% url 'toggle_favorite' recipe.pk %}" class="button circle surface white-text">
18
- <i class="{% if recipe in user.favorites.all %}primary-text{% else %}black-text{% endif %}">
17
+ <a href="{% url 'toggle_favorite' recipe.pk %}" class="button circle transparent">
18
+ <i class="{% if recipe in user.favorites.all %}red-text{% else %}black-text{% endif %}">
19
19
  {% if recipe in user.favorites.all %}favorite{% else %}favorite_border{% endif %}
20
20
  </i>
21
21
  </a>
22
22
  </div>
23
23
  {% endif %}
24
+ {% if user.is_authenticated and recipe.price %}
25
+ <div class="absolute top right padding">
26
+ <form action="{% url 'add_to_cart' recipe.pk %}" method="post" class="ml-1">
27
+ {% csrf_token %}
28
+ <button type="submit" class="button circle primary" title="{% trans 'Add to Cart' %}">
29
+ <i>add_shopping_cart</i>
30
+ </button>
31
+ </form>
32
+ </div>
33
+ {% endif %}
24
34
  </div>
25
35
 
26
- <div class="padding">
36
+ <div class="padding grow">
27
37
  <h5 class="truncate pointer" onclick="location.href='{% url 'recipe_detail' recipe.slug %}';">{{ recipe.title }}</h5>
28
-
29
38
  {% if recipe.price %}
30
39
  <div class="row align-center mb-1">
31
40
  <i class="small-text primary-text">euro_symbol</i>
@@ -48,23 +57,27 @@
48
57
  <span class="tiny-text left-margin">{% trans "Unknown" %}</span>
49
58
  {% endif %}
50
59
  </div>
51
-
52
60
  <div class="space"></div>
53
-
54
61
  <div class="row wrap">
55
- {% if recipe.favorited_by.all %}
62
+ {% with favoriters=recipe.favorited_by.all %}
63
+ {% with count=favoriters.count %}
64
+ {% if count > 0 %}
56
65
  <span class="tiny-text">
57
- {% if recipe.favorited_by.count == 1 %}
58
- {% trans "Liked by" %} {{ recipe.favorited_by.first.username }}
66
+ {% trans "Liked by" %}
67
+ {% if count == 1 %}
68
+ {{ favoriters.0.username }}
69
+ {% elif count == 2 %}
70
+ {{ favoriters.0.username }} {% trans "and" %} {{ favoriters.1.username }}
59
71
  {% else %}
60
- {% trans "Liked by" %} {{ recipe.favorited_by.first.username }} {% trans "and" %} {{ recipe.favorited_by.count|add:"-1" }} {% trans "others" %}
72
+ {{ favoriters.0.username }}, {{ favoriters.1.username }} {% trans "and" %} {{ count|add:"-2" }} {% trans "others" %}
61
73
  {% endif %}
62
74
  </span>
63
75
  {% endif %}
76
+ {% endwith %}
77
+ {% endwith %}
64
78
  </div>
65
79
 
66
80
  <div class="space"></div>
67
-
68
81
  <div class="row wrap">
69
82
  {% for tag in recipe.tags.all %}
70
83
  <a href="{% url 'index' %}?tag={{ tag.name|urlencode }}" class="chip small round surface margin-bottom">{{ tag.name }}</a>
@@ -77,14 +90,6 @@
77
90
  <span>{% trans 'View' %}</span>
78
91
  <i class="suffix">arrow_forward</i>
79
92
  </a>
80
- {% if user.is_authenticated and recipe.price %}
81
- <form action="{% url 'add_to_cart' recipe.pk %}" method="post" class="ml-1">
82
- {% csrf_token %}
83
- <button type="submit" class="button circle primary" title="{% trans 'Add to Cart' %}">
84
- <i>add_shopping_cart</i>
85
- </button>
86
- </form>
87
- {% endif %}
88
93
  </div>
89
94
  </article>
90
95
  </div>
@@ -5,8 +5,7 @@
5
5
  {% block content %}
6
6
  <div class="large-space"></div>
7
7
 
8
- <div class="grid">
9
- <div class="s12 m10 l8 xl6 middle-align center-align" style="margin: 0 auto;">
8
+ <div class="s12 m10 l8 xl6 middle-align center-align" >
10
9
  <article class="round elevate">
11
10
  <div class="padding">
12
11
  <h4 class="center-align primary-text">{% trans "Edit your profile" %}</h4>
@@ -73,7 +72,7 @@
73
72
  </label>
74
73
  </div>
75
74
  {% if user.avatar %}
76
- <img src="{{ user.avatar.url }}" class="circle small">
75
+ <img src="{{ user.avatar.url }}" class="circle">
77
76
  {% endif %}
78
77
  </nav>
79
78
  {% if form.avatar.errors %}
@@ -91,13 +90,13 @@
91
90
 
92
91
  </form>
93
92
  </article>
93
+ </div>
94
94
 
95
95
  <div class="large-space"></div>
96
-
97
- <h4 class="center-align primary-text">{% trans "Order History" %}</h4>
98
-
96
+ <div class="middle-align center-align ">
97
+ <h4 class="center-align padding">{% trans "Order History" %}</h4>
99
98
  <form method="get" class="row no-wrap middle-align">
100
- <div class="field label border round small">
99
+ <div class="field label border round">
101
100
  <select name="status" onchange="this.form.submit()">
102
101
  <option value="">{% trans "All Statuses" %}</option>
103
102
  {% for code, label in status_choices %}
@@ -107,7 +106,7 @@
107
106
  <label>{% trans "Filter by Status" %}</label>
108
107
  </div>
109
108
  <div class="space"></div>
110
- <div class="field label border round small">
109
+ <div class="field label border round">
111
110
  <select name="sort" onchange="this.form.submit()">
112
111
  <option value="date_desc" {% if current_sort == 'date_desc' %}selected{% endif %}>{% trans "Newest First" %}</option>
113
112
  <option value="date_asc" {% if current_sort == 'date_asc' %}selected{% endif %}>{% trans "Oldest First" %}</option>
@@ -117,18 +116,19 @@
117
116
  <label>{% trans "Sort by" %}</label>
118
117
  </div>
119
118
  </form>
119
+ </div>
120
120
 
121
121
  {% if orders %}
122
122
  <div class="padding border round surface left-align">
123
- <table class="border striped">
123
+ <table class="border striped large-space">
124
124
  <thead>
125
125
  <tr>
126
- <th class="min">#</th>
127
- <th class="max">{% trans "Recipe" %}</th>
128
- <th class="min">{% trans "Date" %}</th>
129
- <th class="min">{% trans "Status" %}</th>
130
- <th class="min">{% trans "Price" %}</th>
131
- <th class="min"></th>
126
+ <th>{% trans "Order Id" %}</th>
127
+ <th>{% trans "Recipe" %}</th>
128
+ <th>{% trans "Date" %}</th>
129
+ <th>{% trans "Status" %}</th>
130
+ <th>{% trans "Price" %}</th>
131
+ <th>{% trans "View Order" %}</th>
132
132
  </tr>
133
133
  </thead>
134
134
  <tbody>
@@ -138,13 +138,13 @@
138
138
  <td>
139
139
  <a href="{% url 'recipe_detail' order.recipe.slug %}">{{ order.recipe.title }}</a>
140
140
  </td>
141
- <td class="no-wrap">{{ order.created_at|date:"d/m/Y" }}</td>
141
+ <td>{{ order.created_at|date:"d/m/Y" }}</td>
142
142
  <td>
143
143
  <span class="chip tiny {% if order.status == 'PENDING' %}surface-variant{% elif order.status == 'COMPLETED' %}primary{% elif order.status == 'CANCELLED' %}error{% else %}secondary{% endif %}">
144
144
  {{ order.get_status_display }}
145
145
  </span>
146
146
  </td>
147
- <td class="no-wrap">{{ order.total_price }} €</td>
147
+ <td>{{ order.total_price }} €</td>
148
148
  <td>
149
149
  <a href="{% url 'user_order_detail' order.id %}" class="button circle transparent small">
150
150
  <i>visibility</i>
@@ -182,5 +182,5 @@
182
182
  </div>
183
183
  {% endif %}
184
184
  </div>
185
- </div>
185
+
186
186
  {% endblock %}
@@ -120,7 +120,13 @@ urlpatterns += i18n_patterns(
120
120
  views.admin_rating_delete,
121
121
  name="admin_rating_delete",
122
122
  ),
123
+ path("dashboard/settings/", views.admin_settings, name="admin_settings"),
123
124
  path("dashboard/orders/", views.admin_order_list, name="admin_order_list"),
125
+ path(
126
+ "dashboard/orders/<int:pk>/status/",
127
+ views.admin_order_update_status,
128
+ name="admin_order_update_status",
129
+ ),
124
130
  prefix_default_language=True,
125
131
  )
126
132
 
@@ -51,6 +51,9 @@ COMMON_UNITS = {
51
51
  "to taste",
52
52
  }
53
53
 
54
+ # Simple in-memory DB for order status tracking
55
+ ORDER_DB = {}
56
+
54
57
 
55
58
  def parse_ingredient_line(line):
56
59
  """
@@ -9,7 +9,8 @@ from django.contrib.auth.decorators import login_required
9
9
  from django.contrib.admin.views.decorators import staff_member_required
10
10
  from django.utils.translation import gettext as _
11
11
  from django.utils import translation
12
- from .models import Recipe, Rating, Tag, Order, CartItem
12
+ from .models import Recipe, Rating, Tag, Order, CartItem, Setting
13
+ from .utils import ORDER_DB
13
14
  from .forms import (
14
15
  RecipeForm,
15
16
  AdminSetupForm,
@@ -20,6 +21,7 @@ from .forms import (
20
21
  UserProfileForm,
21
22
  UserRecipeSubmissionForm,
22
23
  UserSettingsForm,
24
+ SettingForm,
23
25
  )
24
26
  from django.http import HttpResponseBadRequest, Http404
25
27
  from django.conf import settings
@@ -491,6 +493,52 @@ def admin_rating_delete(request, pk):
491
493
  )
492
494
 
493
495
 
496
+ @staff_member_required
497
+ def admin_settings(request):
498
+ instance = Setting.get_solo()
499
+ if request.method == "POST":
500
+ form = SettingForm(request.POST, request.FILES, instance=instance)
501
+ if form.is_valid():
502
+ form.save()
503
+ messages.success(request, _("Site settings updated successfully."))
504
+ return redirect("admin_settings")
505
+ else:
506
+ form = SettingForm(instance=instance)
507
+ return render(
508
+ request,
509
+ "admin/settings.html",
510
+ {"form": form, "title": _("Site Settings"), "version": sandwitches_version},
511
+ )
512
+
513
+
514
+ @staff_member_required
515
+ def admin_order_update_status(request, pk):
516
+ order = get_object_or_404(Order, pk=pk)
517
+ if request.method == "POST":
518
+ new_status = request.POST.get("status")
519
+ if new_status in dict(Order.STATUS_CHOICES):
520
+ # Immutability check: if status is CANCELLED or COMPLETED, it shouldn't be changed
521
+ if order.status in ["COMPLETED", "CANCELLED"]:
522
+ messages.error(
523
+ request,
524
+ _("Cannot change status of a completed or cancelled order."),
525
+ )
526
+ else:
527
+ order.status = new_status
528
+ if new_status == "COMPLETED":
529
+ order.completed = True
530
+ order.save()
531
+
532
+ # Update ORDER_DB
533
+ ORDER_DB[order.pk] = new_status
534
+
535
+ messages.success(request, _("Order status updated."))
536
+ else:
537
+ messages.error(request, _("Invalid status."))
538
+
539
+ return redirect("admin_order_list")
540
+
541
+
494
542
  @staff_member_required
495
543
  def admin_order_list(request):
496
544
  orders = (
@@ -503,13 +551,21 @@ def admin_order_list(request):
503
551
  return render(
504
552
  request,
505
553
  "admin/partials/order_rows.html",
506
- {"orders": orders, "version": sandwitches_version},
554
+ {
555
+ "orders": orders,
556
+ "version": sandwitches_version,
557
+ "status_choices": Order.STATUS_CHOICES,
558
+ },
507
559
  )
508
560
 
509
561
  return render(
510
562
  request,
511
563
  "admin/order_list.html",
512
- {"orders": orders, "version": sandwitches_version},
564
+ {
565
+ "orders": orders,
566
+ "version": sandwitches_version,
567
+ "status_choices": Order.STATUS_CHOICES,
568
+ },
513
569
  )
514
570
 
515
571
 
@@ -1,28 +0,0 @@
1
- {% load i18n %}
2
- {% for order in orders %}
3
- <tr>
4
- <td>{{ order.id }}</td>
5
- <td>
6
- <div class="row align-center">
7
- {% if order.user.avatar %}
8
- <img src="{{ order.user.avatar.url }}" class="circle tiny">
9
- {% else %}
10
- <i class="circle tiny">person</i>
11
- {% endif %}
12
- <span class="max">{{ order.user.username }}</span>
13
- </div>
14
- </td>
15
- <td>{{ order.recipe.title }}</td>
16
- <td>{{ order.total_price }} €</td>
17
- <td>
18
- <span class="chip {% if order.status == 'PENDING' %}surface-variant{% elif order.status == 'COMPLETED' %}primary{% elif order.status == 'CANCELLED' %}error{% else %}secondary{% endif %}">
19
- {{ order.get_status_display }}
20
- </span>
21
- </td>
22
- <td>{{ order.created_at|date:"d/m/Y H:i" }}</td>
23
- </tr>
24
- {% empty %}
25
- <tr>
26
- <td colspan="6" class="center-align">{% trans "No orders found." %}</td>
27
- </tr>
28
- {% endfor %}
File without changes