fix: huge refactor
This commit is contained in:
@@ -210,5 +210,3 @@ SIMPLE_JWT = {
|
|||||||
'SLIDING_TOKEN_OBTAIN_SERIALIZER': 'rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer',
|
'SLIDING_TOKEN_OBTAIN_SERIALIZER': 'rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer',
|
||||||
'SLIDING_TOKEN_REFRESH_SERIALIZER': 'rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer',
|
'SLIDING_TOKEN_REFRESH_SERIALIZER': 'rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer',
|
||||||
}
|
}
|
||||||
|
|
||||||
TAILWIND_APP_NAME = 'theme'
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from django.urls import include, path
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', include('web.urls', namespace='web')),
|
path('', include('web.urls', namespace='web')),
|
||||||
|
path('users/', include('users.urls', namespace='users')),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('watchman/', include('watchman.urls')),
|
path('watchman/', include('watchman.urls')),
|
||||||
path('auth/', include('users.urls', namespace='users')),
|
path('auth/', include('users.urls', namespace='users')),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,11 +9,11 @@ class LoginForm(StylingMixin, AuthenticationForm):
|
|||||||
styled_fields = []
|
styled_fields = []
|
||||||
placeholder_for_field = {'username': _('pablo@shoppy.com'), 'password': '********'}
|
placeholder_for_field = {'username': _('pablo@shoppy.com'), 'password': '********'}
|
||||||
|
|
||||||
username = UsernameField(widget=forms.EmailInput(attrs={'autofocus': True, 'class': 'input-text'}))
|
username = UsernameField(widget=forms.EmailInput(attrs={'autofocus': True, 'class': 'input w-full'}))
|
||||||
password = forms.CharField(
|
password = forms.CharField(
|
||||||
label=_('Contraseña'),
|
label=_('Contraseña'),
|
||||||
strip=False,
|
strip=False,
|
||||||
widget=forms.PasswordInput(attrs={'autocomplete': 'current-password', 'class': 'input-text'}),
|
widget=forms.PasswordInput(attrs={'autocomplete': 'current-password', 'class': 'input w-full'}),
|
||||||
)
|
)
|
||||||
remember_me = forms.BooleanField(
|
remember_me = forms.BooleanField(
|
||||||
label=_('Mantener sesión iniciada'),
|
label=_('Mantener sesión iniciada'),
|
||||||
|
|||||||
@@ -24,10 +24,7 @@ class RegisterForm(StylingMixin, BaseUserCreationForm, SetPasswordMixin):
|
|||||||
self.fields[field_name].required = True
|
self.fields[field_name].required = True
|
||||||
self.fields[field_name].widget.attrs.update(
|
self.fields[field_name].widget.attrs.update(
|
||||||
{
|
{
|
||||||
'class': 'my-2 bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg '
|
'class': 'input w-full'
|
||||||
'focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 '
|
|
||||||
'dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 '
|
|
||||||
'dark:focus:border-primary-500'
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2,27 +2,27 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<section class="bg-gray-50 dark:bg-gray-900">
|
<section class=" ">
|
||||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||||
|
|
||||||
<a href="{% url 'web:index' %}"
|
<a href="{% url 'web:index' %}"
|
||||||
class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
class="flex items-center mb-6 text-2xl font-semibold ">
|
||||||
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
||||||
{{ web_title }}
|
{{ web_title }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
class="w-full rounded-lg shadow md:mt-0 sm:max-w-md xl:p-0 ">
|
||||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||||
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
<h1 class="text-xl font-bold leading-tight tracking-tight md:text-2xl ">
|
||||||
{% translate 'Inicia sesión en tu cuenta' %}
|
{% translate 'Inicia sesión en tu cuenta' %}
|
||||||
</h1>
|
</h1>
|
||||||
<form action="{% url 'web:login' %}{% querystring %}" method="post">
|
<form action="{% url 'users:login' %}{% querystring %}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
{% if field.id_for_label != 'id_remember_me' %}
|
{% if field.id_for_label != 'id_remember_me' %}
|
||||||
<label for="{{ field.id_for_label }}"
|
<label for="{{ field.id_for_label }}"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{{ field.label }}
|
{{ field.label }}
|
||||||
</label>
|
</label>
|
||||||
{{ field }}
|
{{ field }}
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
<div class="my-2 flex items-center">
|
<div class="my-2 flex items-center">
|
||||||
{{ field }}
|
{{ field }}
|
||||||
<label for="{{ field.id_for_label }}"
|
<label for="{{ field.id_for_label }}"
|
||||||
class="inline-block text-sm font-medium text-gray-900 dark:text-white ml-2">
|
class="inline-block text-sm font-medium ml-2">
|
||||||
{{ field.label }}
|
{{ field.label }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,27 +38,27 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<p class="text-sm font-light text-gray-500 my-4 dark:text-gray-400">
|
<p class="text-sm font-light my-4 ">
|
||||||
{% translate '¿Aún no tienes cuenta?' %}
|
{% translate '¿Aún no tienes cuenta?' %}
|
||||||
<a href="{% url 'web:register' %}"
|
<a href="{% url 'users:register' %}"
|
||||||
class="font-medium text-primary-700 hover:underline dark:text-primary-400">{% translate 'Regístrate aquí' %}</a>
|
class="font-medium text-primary-700 hover:underline ">{% translate 'Regístrate aquí' %}</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% for k, error in form.errors.items %}
|
{% for k, error in form.errors.items %}
|
||||||
<span class="flex justify-center mb-2 text-sm font-medium text-red-900 dark:text-red-400">{{ error }}</span>
|
<span class="flex justify-center mb-2 text-sm font-medium text-red-900 ">{{ error }}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 cursor-pointer">
|
class="w-full btn btn-primary">
|
||||||
{% translate 'Iniciar sesión' %}
|
{% translate 'Iniciar sesión' %}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<p class="text-sm font-light text-gray-500 mt-4 dark:text-gray-400">
|
<p class="text-sm font-light mt-4 ">
|
||||||
<a href="{% url 'web:reset_password' %}"
|
<a href="{% url 'users:reset_password' %}"
|
||||||
class="font-medium text-primary-700 hover:underline dark:text-primary-400">{% translate '¿Has olvidado tu contraseña?' %}</a>
|
class="font-medium text-primary-700 hover:underline ">{% translate '¿Has olvidado tu contraseña?' %}</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -2,26 +2,26 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<section class="bg-gray-50 dark:bg-gray-900">
|
<section class=" ">
|
||||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||||
|
|
||||||
<a href="{% url 'web:index' %}" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
<a href="{% url 'web:index' %}" class="flex items-center mb-6 text-2xl font-semibold ">
|
||||||
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
||||||
{{ web_title }}
|
{{ web_title }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
class="w-full rounded-lg shadow md:mt-0 sm:max-w-md xl:p-0 ">
|
||||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||||
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
<h1 class="text-xl font-bold leading-tight tracking-tight md:text-2xl ">
|
||||||
{% translate 'Crea tu cuenta' %}
|
{% translate 'Crea tu cuenta' %}
|
||||||
</h1>
|
</h1>
|
||||||
<form action="{% url 'web:register' %}" method="post">
|
<form action="{% url 'users:register' %}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
<div class="my-2">
|
<div class="my-2">
|
||||||
<label for="{{ field.id_for_label }}"
|
<label for="{{ field.id_for_label }}"
|
||||||
class="inline-block text-sm font-medium text-gray-900 dark:text-white mr-2">
|
class="inline-block text-sm font-medium mr-2">
|
||||||
{{ field.label }}
|
{{ field.label }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@@ -32,18 +32,16 @@
|
|||||||
|
|
||||||
{% if errors %}
|
{% if errors %}
|
||||||
{% for error in errors %}
|
{% for error in errors %}
|
||||||
<span class="inline-block text-sm font-medium text-red-900 dark:text-red-400 mr-2">{{ error }}</span>
|
<span class="inline-block text-sm font-medium text-red-900 mr-2">{{ error }}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<button class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none
|
<button class="w-full btn btn-primary">
|
||||||
focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center
|
|
||||||
dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 mt-4 cursor-pointer">
|
|
||||||
{% translate 'Crear cuenta' %}
|
{% translate 'Crear cuenta' %}
|
||||||
</button>
|
</button>
|
||||||
<p class="text-sm font-light text-gray-500 mt-4 dark:text-gray-400">
|
<p class="text-sm font-light mt-4 ">
|
||||||
{% translate '¿Ya tienes cuenta?' %}
|
{% translate '¿Ya tienes cuenta?' %}
|
||||||
<a href="{% url 'web:login' %}" class="font-medium text-primary-600 hover:underline dark:text-primary-500">{% translate 'Inicia sesión aquí' %}</a>
|
<a href="{% url 'users:login' %}" class="font-medium text-primary-600 hover:underline ">{% translate 'Inicia sesión aquí' %}</a>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
{% extends 'theme/base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<section class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||||
|
<a href="{% url 'web:index' %}" class="flex items-center mb-6 text-2xl font-semibold ">
|
||||||
|
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
||||||
|
{{ web_title }}
|
||||||
|
</a>
|
||||||
|
<div
|
||||||
|
class="w-full rounded-lg shadow md:mt-0 sm:max-w-md xl:p-0 ">
|
||||||
|
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||||
|
<h1 class="text-xl font-bold leading-tight tracking-tight md:text-2xl ">
|
||||||
|
{% translate 'Restablecer contraseña' %}
|
||||||
|
</h1>
|
||||||
|
<form action="{% url 'users:reset_password' %}" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% for field in form %}
|
||||||
|
|
||||||
|
<div class="my-2">
|
||||||
|
<label for="{{ field.id_for_label }}"
|
||||||
|
class="inline-block text-sm font-medium mr-2">
|
||||||
|
{{ field.label }}
|
||||||
|
</label>
|
||||||
|
{{ field }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
<button
|
||||||
|
class="btn btn-primary w-full">
|
||||||
|
{% translate 'Restablecer contraseña' %}
|
||||||
|
</button>
|
||||||
|
<p class="text-sm font-light mt-4 ">
|
||||||
|
{% translate '¿Aún no tienes cuenta?' %}
|
||||||
|
<a href="{% url 'users:register' %}"
|
||||||
|
class="font-medium text-primary-600 hover:underline ">{% translate 'Regístrate aquí' %}</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
+8
-8
@@ -2,18 +2,18 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<section class="bg-gray-50 dark:bg-gray-900">
|
<section class=" ">
|
||||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||||
|
|
||||||
<a href="{% url 'web:index' %}" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
<a href="{% url 'web:index' %}" class="flex items-center mb-6 text-2xl font-semibold ">
|
||||||
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
||||||
{{ web_title }}
|
{{ web_title }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
class="w-full rounded-lg shadow md:mt-0 sm:max-w-md xl:p-0 ">
|
||||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||||
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
<h1 class="text-xl font-bold leading-tight tracking-tight md:text-2xl ">
|
||||||
{% translate 'Restablecer contraseña' %}
|
{% translate 'Restablecer contraseña' %}
|
||||||
</h1>
|
</h1>
|
||||||
{% if valid_token %}
|
{% if valid_token %}
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<div class="my-2">
|
<div class="my-2">
|
||||||
<label for="{{ field.id_for_label }}"
|
<label for="{{ field.id_for_label }}"
|
||||||
class="inline-block text-sm font-medium text-gray-900 dark:text-white mr-2">
|
class="inline-block text-sm font-medium mr-2">
|
||||||
{{ field.label }}
|
{{ field.label }}
|
||||||
</label>
|
</label>
|
||||||
{{ field }}
|
{{ field }}
|
||||||
@@ -31,12 +31,12 @@
|
|||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<button
|
<button
|
||||||
class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 cursor-pointer">
|
class="w-full btn btn-primary">
|
||||||
{% translate 'Restablecer contraseña' %}
|
{% translate 'Restablecer contraseña' %}
|
||||||
</button>
|
</button>
|
||||||
<p class="text-sm font-light text-gray-500 mt-4 dark:text-gray-400">
|
<p class="text-sm font-light mt-4 ">
|
||||||
{% translate '¿Aún no tienes cuenta?' %}
|
{% translate '¿Aún no tienes cuenta?' %}
|
||||||
<a href="{% url 'web:register' %}" class="font-medium text-primary-600 hover:underline dark:text-primary-500">{% translate 'Regístrate aquí' %}</a>
|
<a href="{% url 'users:register' %}" class="font-medium text-primary-600 hover:underline ">{% translate 'Regístrate aquí' %}</a>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
+7
-7
@@ -2,26 +2,26 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<section class="bg-gray-50 dark:bg-gray-900">
|
<section class=" ">
|
||||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||||
|
|
||||||
<a href="{% url 'web:index' %}"
|
<a href="{% url 'web:index' %}"
|
||||||
class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
class="flex items-center mb-6 text-2xl font-semibold ">
|
||||||
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
||||||
{{ web_title }}
|
{{ web_title }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
class="w-full rounded-lg shadow md:mt-0 sm:max-w-md xl:p-0 ">
|
||||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||||
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
<h1 class="text-xl font-bold leading-tight tracking-tight md:text-2xl ">
|
||||||
{% translate 'Se te ha enviado un correo electrónico para restablecer tu contraseña' %}
|
{% translate 'Se te ha enviado un correo electrónico para restablecer tu contraseña' %}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p class="text-sm font-light text-gray-500 mt-4 dark:text-gray-400">
|
<p class="text-sm font-light mt-4 ">
|
||||||
{% translate '¿Aún no tienes cuenta?' %}
|
{% translate '¿Aún no tienes cuenta?' %}
|
||||||
<a href="{% url 'web:register' %}"
|
<a href="{% url 'users:register' %}"
|
||||||
class="font-medium text-primary-600 hover:underline dark:text-primary-500">{% translate 'Regístrate aquí' %}</a>
|
class="font-medium text-primary-600 hover:underline ">{% translate 'Regístrate aquí' %}</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2,19 +2,16 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{% include 'components/generic/navbar.html' %}
|
{% include 'components/generic/navbar.html' %}
|
||||||
<section class="bg-white py-8 antialiased dark:bg-gray-900 md:py-8">
|
<section class=" py-8 antialiased md:py-8">
|
||||||
<div class="mx-auto max-w-screen-lg px-4 2xl:px-0">
|
<div class="mx-auto max-w-screen-lg px-4 2xl:px-0">
|
||||||
<h2
|
<h2
|
||||||
class="mb-4 text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl md:mb-6"
|
class="mb-4 text-xl font-semibold sm:text-2xl md:mb-6"
|
||||||
>
|
>
|
||||||
{% translate 'Mi cuenta' %}
|
{% translate 'Mi cuenta' %}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="md:grid md:grid-cols-2 md:gap-4">
|
<div class="md:grid md:grid-cols-2 md:gap-4">
|
||||||
<section
|
<section class="p-6 rounded-md">
|
||||||
class="p-6 border border-gray-100 rounded-md dark:border-gray-600"
|
<h2 class="mb-4 text-xl font-semibold sm:text-2xl md:mb-6">
|
||||||
|
|
||||||
>
|
|
||||||
<h2 class="mb-4 text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl md:mb-6">
|
|
||||||
{% translate 'Datos de usuario' %}
|
{% translate 'Datos de usuario' %}
|
||||||
</h2>
|
</h2>
|
||||||
<div hx-get="{% url 'web:user_info_component' %}" hx-trigger="load, updated_user_info">
|
<div hx-get="{% url 'web:user_info_component' %}" hx-trigger="load, updated_user_info">
|
||||||
@@ -25,9 +22,9 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section
|
<section
|
||||||
class="p-6 border border-gray-100 rounded-md dark:border-gray-600 mt-4 md:mt-0"
|
class="p-6 rounded-md mt-4 md:mt-0"
|
||||||
>
|
>
|
||||||
<h2 class="mb-4 text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl md:mb-6">
|
<h2 class="mb-4 text-xl font-semibold sm:text-2xl md:mb-6">
|
||||||
{% translate 'Contraseña' %}
|
{% translate 'Contraseña' %}
|
||||||
</h2>
|
</h2>
|
||||||
<div hx-get="{% url 'web:change_password_component' %}" hx-trigger="load, changed_password">
|
<div hx-get="{% url 'web:change_password_component' %}" hx-trigger="load, changed_password">
|
||||||
@@ -38,19 +35,19 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 p-6 border border-gray-100 rounded-md dark:border-gray-600">
|
<div class="mt-4 p-6 rounded-md ">
|
||||||
<div class="flex space-x-4">
|
<div class="flex space-x-4">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="flex items-center text-xl font-bold leading-none text-gray-900 dark:text-white sm:text-2xl">
|
<h3 class="flex items-center text-xl font-bold leading-none sm:text-2xl">
|
||||||
{% translate 'Mis direcciones' %}
|
{% translate 'Mis direcciones' %}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<hr class="h-px my-2 bg-gray-200 border-0 dark:bg-gray-700">
|
<hr class="h-px my-2 ">
|
||||||
|
|
||||||
{% if customer_addresses.count == 0 %}
|
{% if customer_addresses.count == 0 %}
|
||||||
<span class="text-gray-500 dark:text-gray-400">{% translate 'No hay ninguna dirección' %}</span>
|
<span class=" ">{% translate 'No hay ninguna dirección' %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div hx-get="{% url 'web:list_customer_addresses_component' %}" hx-trigger="load, updated_addresses">
|
<div hx-get="{% url 'web:list_customer_addresses_component' %}" hx-trigger="load, updated_addresses">
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.shortcuts import reverse
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
class TestLogin(TestCase):
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.password = 'theonering'
|
||||||
|
self.user = User.objects.create(username='sauron', email='sauron@mordor.middleearth')
|
||||||
|
|
||||||
|
self.user.set_password(self.password)
|
||||||
|
self.user.save()
|
||||||
|
|
||||||
|
def test_login(self):
|
||||||
|
response = self.client.post(reverse('users:login'), {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
|
def test_login_get(self):
|
||||||
|
response = self.client.get(reverse('users:login'))
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
def test_login_already_logged_in(self):
|
||||||
|
response = self.client.post(reverse('users:login'), {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
|
response = self.client.get(reverse('users:login'))
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
|
def test_login_failed(self):
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('users:login'), {'username': self.user.username, 'password': 'wrongpassword'}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
def test_login_then_logout(self):
|
||||||
|
response = self.client.post(reverse('users:login'), {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
|
response = self.client.post(reverse('web:logout'))
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
|
def test_logout_already_logged_out(self):
|
||||||
|
response = self.client.post(reverse('web:logout'))
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
|
def test_login_then_get_logout(self):
|
||||||
|
response = self.client.post(reverse('users:login'), {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
|
response = self.client.get(reverse('web:logout'))
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
|
def test_login_then_get_my_account(self):
|
||||||
|
response = self.client.post(reverse('users:login'), {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
|
response = self.client.get(reverse('web:my_account'))
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
def test_login_redirection_to_my_account(self):
|
||||||
|
url = f'{reverse("users:login")}?next={reverse("web:my_account")}'
|
||||||
|
response = self.client.post(url, {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == f'{reverse("web:index")}?next={reverse("web:my_account")}'
|
||||||
|
|
||||||
|
response = self.client.get(response.url)
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:my_account')
|
||||||
|
|
||||||
|
def test_login_redirection_to_my_orders(self):
|
||||||
|
url = f'{reverse("users:login")}?next={reverse("web:orders")}'
|
||||||
|
response = self.client.post(url, {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == f'{reverse("web:index")}?next={reverse("web:orders")}'
|
||||||
|
|
||||||
|
response = self.client.get(response.url)
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('web:orders')
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.shortcuts import reverse
|
||||||
|
from django.test import TransactionTestCase
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
class TestRegister(TransactionTestCase):
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.password = 'theonering'
|
||||||
|
self.email = 'sauron@mordor.middleearth'
|
||||||
|
self.first_name = 'Sauron'
|
||||||
|
self.last_name = 'The Lord of the Rings'
|
||||||
|
|
||||||
|
def test_get_register_page(self):
|
||||||
|
response = self.client.get(reverse('users:register'))
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
def test_create_user_account(self):
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('users:register'),
|
||||||
|
{
|
||||||
|
'email': self.email,
|
||||||
|
'password1': self.password,
|
||||||
|
'password2': self.password,
|
||||||
|
'first_name': self.first_name,
|
||||||
|
'last_name': self.last_name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
user = User.objects.filter(
|
||||||
|
username=self.email, email=self.email, first_name=self.first_name, last_name=self.last_name
|
||||||
|
).first()
|
||||||
|
|
||||||
|
assert user is not None
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('users:login')
|
||||||
|
|
||||||
|
def test_create_user_account_distinct_password(self):
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('users:register'),
|
||||||
|
{
|
||||||
|
'email': self.email,
|
||||||
|
'password1': self.password,
|
||||||
|
'password2': 'otherpassword',
|
||||||
|
'first_name': self.first_name,
|
||||||
|
'last_name': self.last_name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not User.objects.filter(
|
||||||
|
username=self.email, email=self.email, first_name=self.first_name, last_name=self.last_name
|
||||||
|
).exists()
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
def test_create_user_account_no_first_name(self):
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('users:register'),
|
||||||
|
{
|
||||||
|
'email': self.email,
|
||||||
|
'password1': self.password,
|
||||||
|
'password2': 'otherpassword',
|
||||||
|
'first_name': '',
|
||||||
|
'last_name': self.last_name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not User.objects.filter(
|
||||||
|
username=self.email, email=self.email, first_name='', last_name=self.last_name
|
||||||
|
).exists()
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
def test_create_user_account_no_last_name(self):
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('users:register'),
|
||||||
|
{
|
||||||
|
'email': self.email,
|
||||||
|
'password1': self.password,
|
||||||
|
'password2': self.password,
|
||||||
|
'first_name': self.first_name,
|
||||||
|
'last_name': '',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not User.objects.filter(
|
||||||
|
username=self.email, email=self.email, first_name=self.first_name, last_name=''
|
||||||
|
).exists()
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
def test_create_user_account_already_existing(self):
|
||||||
|
assert User.objects.all().count() == 0
|
||||||
|
User.objects.create_user(email=self.email, username=self.email)
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('users:register'),
|
||||||
|
{
|
||||||
|
'email': self.email,
|
||||||
|
'password1': self.password,
|
||||||
|
'password2': self.password,
|
||||||
|
'first_name': self.first_name,
|
||||||
|
'last_name': self.last_name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not User.objects.filter(
|
||||||
|
username=self.email, email=self.email, first_name=self.first_name, last_name=''
|
||||||
|
).exists()
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
|
from django.shortcuts import reverse
|
||||||
|
from django.test import TransactionTestCase
|
||||||
|
from django.utils.encoding import force_bytes
|
||||||
|
from django.utils.http import urlsafe_base64_encode
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
class TestResetPassword(TransactionTestCase):
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.password = 'theonering'
|
||||||
|
self.email = 'sauron@mordor.middleearth'
|
||||||
|
self.first_name = 'Sauron'
|
||||||
|
self.last_name = 'The Lord of the Rings'
|
||||||
|
|
||||||
|
self.user = User.objects.create_user(
|
||||||
|
username=self.email, password=self.password, first_name=self.first_name, last_name=self.last_name
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_reset_password_page(self):
|
||||||
|
response = self.client.get(reverse('users:reset_password'))
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
def test_reset_password(self):
|
||||||
|
response = self.client.post(reverse('users:reset_password'), {'email': self.email})
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('users:reset_password_email_sent')
|
||||||
|
|
||||||
|
def test_reset_password_not_existing_user(self):
|
||||||
|
response = self.client.post(reverse('users:reset_password'), {'email': 'vanpiro@noesiten.com'})
|
||||||
|
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('users:reset_password_email_sent')
|
||||||
|
|
||||||
|
def test_reset_password_confirm_get(self):
|
||||||
|
token = default_token_generator.make_token(self.user)
|
||||||
|
uidb64 = urlsafe_base64_encode(force_bytes(self.user.pk))
|
||||||
|
|
||||||
|
response = self.client.get(reverse('users:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}))
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
def test_reset_password_confirm(self):
|
||||||
|
token = default_token_generator.make_token(self.user)
|
||||||
|
form_token = default_token_generator.make_token(self.user)
|
||||||
|
uidb64 = urlsafe_base64_encode(force_bytes(self.user.pk))
|
||||||
|
|
||||||
|
new_password = '89733wy29'
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('users:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}),
|
||||||
|
{'token': form_token, 'new_password1': new_password, 'new_password2': new_password},
|
||||||
|
)
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse('users:login')
|
||||||
|
self.user.refresh_from_db()
|
||||||
|
|
||||||
|
assert self.user.check_password(new_password)
|
||||||
|
|
||||||
|
def test_reset_password_confirm_distinct_password(self):
|
||||||
|
token = default_token_generator.make_token(self.user)
|
||||||
|
form_token = default_token_generator.make_token(self.user)
|
||||||
|
uidb64 = urlsafe_base64_encode(force_bytes(self.user.pk))
|
||||||
|
|
||||||
|
new_password = '89733wy29'
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('users:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}),
|
||||||
|
{'token': form_token, 'new_password1': new_password, 'new_password2': 'otherpassw13'},
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
def test_reset_password_confirm_invalid_token(self):
|
||||||
|
token = default_token_generator.make_token(self.user)
|
||||||
|
form_token = 'invalid token'
|
||||||
|
uidb64 = urlsafe_base64_encode(force_bytes(self.user.pk))
|
||||||
|
|
||||||
|
new_password = '89733wy29'
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('users:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}),
|
||||||
|
{'token': form_token, 'new_password1': new_password, 'new_password2': new_password},
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
+24
-1
@@ -1,4 +1,27 @@
|
|||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.urls import path
|
||||||
|
from django.utils.text import gettext_lazy as _
|
||||||
|
|
||||||
|
from web.views.users import (
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
my_account,
|
||||||
|
register,
|
||||||
|
reset_password,
|
||||||
|
reset_password_confirm,
|
||||||
|
reset_password_email_sent,
|
||||||
|
)
|
||||||
|
|
||||||
app_name = 'users'
|
app_name = 'users'
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = []
|
urlpatterns = [
|
||||||
|
# users
|
||||||
|
path(_('login/'), login, name='login'),
|
||||||
|
path(_('logout/'), logout, name='logout'),
|
||||||
|
path(_('register/'), register, name='register'),
|
||||||
|
path(_('reset-password/'), reset_password, name='reset_password'),
|
||||||
|
path(_('reset-password/<uidb64>/<token>/'), reset_password_confirm, name='reset_password_confirm'),
|
||||||
|
path(_('reset-password/email-sent/'), reset_password_email_sent, name='reset_password_email_sent'),
|
||||||
|
path(_('my-account/'), login_required(my_account, login_url=_('/login/')), name='my_account'),
|
||||||
|
]
|
||||||
|
|||||||
+244
@@ -0,0 +1,244 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.contrib.auth import login as login_user
|
||||||
|
from django.contrib.auth import logout as logout_user
|
||||||
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.db import IntegrityError
|
||||||
|
from django.shortcuts import redirect, render, reverse
|
||||||
|
from django.utils.http import url_has_allowed_host_and_scheme, urlencode, urlsafe_base64_decode
|
||||||
|
from django.utils.text import gettext_lazy as _
|
||||||
|
from django.views.generic import TemplateView, View
|
||||||
|
|
||||||
|
from shop.models import CustomerAddress
|
||||||
|
from users.forms import LoginForm, PasswordResetForm, RegisterForm, SetPasswordForm
|
||||||
|
from web.models import WebSettings
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
class RedirectionMixin:
|
||||||
|
redirect_to = ''
|
||||||
|
|
||||||
|
def get_redirection(self):
|
||||||
|
return reverse(self.redirect_to)
|
||||||
|
|
||||||
|
|
||||||
|
class LoginView(View, RedirectionMixin):
|
||||||
|
template_name = 'users/login.html'
|
||||||
|
redirect_to = 'web:index'
|
||||||
|
login_form_class = LoginForm
|
||||||
|
|
||||||
|
def get_redirection(self):
|
||||||
|
next_page = self.request.GET.get('next', '')
|
||||||
|
|
||||||
|
if next_page:
|
||||||
|
return f'{reverse(self.redirect_to)}?next={next_page}'
|
||||||
|
|
||||||
|
return reverse(self.redirect_to)
|
||||||
|
|
||||||
|
def get_login_form(self, request):
|
||||||
|
return self.login_form_class(data=request.POST)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
return redirect(self.get_redirection())
|
||||||
|
|
||||||
|
web_settings = WebSettings.load()
|
||||||
|
login_form = self.login_form_class()
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
self.template_name,
|
||||||
|
{'form': login_form, 'title': web_settings.web_title, 'description': _('inicio de sesión')},
|
||||||
|
)
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
login_form = self.get_login_form(request)
|
||||||
|
|
||||||
|
if login_form.is_valid():
|
||||||
|
login_user(request, login_form.get_user())
|
||||||
|
|
||||||
|
if not login_form.cleaned_data.get('remember_me'):
|
||||||
|
request.session.set_expiry(0)
|
||||||
|
|
||||||
|
return redirect(self.get_redirection())
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request, self.template_name, {'form': login_form, 'errors': login_form.errors.get('__all__')}, status=400
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RegisterView(TemplateView, RedirectionMixin):
|
||||||
|
template_name = 'users/register.html'
|
||||||
|
redirect_to = 'users:login'
|
||||||
|
form_class = RegisterForm
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
settings = WebSettings.load()
|
||||||
|
|
||||||
|
return {'form': self.form_class(), 'title': settings.web_title, 'description': _('crear cuenta')}
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
settings = WebSettings.load()
|
||||||
|
form = self.form_class(request.POST)
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
if form.is_valid():
|
||||||
|
user = form.save()
|
||||||
|
|
||||||
|
user.username = user.email
|
||||||
|
user.first_name = form.cleaned_data.get('first_name')
|
||||||
|
user.last_name = form.cleaned_data.get('last_name')
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
login(request, user)
|
||||||
|
return redirect(self.get_redirection())
|
||||||
|
else:
|
||||||
|
errors = form.errors
|
||||||
|
except IntegrityError:
|
||||||
|
errors = [_('Ya existe un usuario con ese correo electrónico')]
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
self.template_name,
|
||||||
|
{'form': form, 'title': settings.web_title, 'description': _('Crear cuenta'), 'errors': errors},
|
||||||
|
status=400,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LogoutView(View, RedirectionMixin):
|
||||||
|
redirect_to = 'web:index'
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
logout_user(request)
|
||||||
|
return redirect(self.get_redirection())
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
logout_user(request)
|
||||||
|
return redirect(self.get_redirection())
|
||||||
|
|
||||||
|
|
||||||
|
class ResetPasswordView(TemplateView):
|
||||||
|
template_name = 'users/reset_password.html'
|
||||||
|
form_class = PasswordResetForm
|
||||||
|
redirect_to = 'users:reset_password_email_sent'
|
||||||
|
html_reset_password_template_name = 'mails/reset_password.html'
|
||||||
|
subject_template_name = 'mails/subject_reset_password.txt'
|
||||||
|
|
||||||
|
def get_email_options(self):
|
||||||
|
return {
|
||||||
|
'extra_email_context': {},
|
||||||
|
'email_template_name': self.html_reset_password_template_name,
|
||||||
|
'html_email_template_name': self.html_reset_password_template_name,
|
||||||
|
'subject_template_name': self.subject_template_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_base_context(self):
|
||||||
|
settings = WebSettings.load()
|
||||||
|
|
||||||
|
return {'title': settings.web_title, 'description': _('Restablecer contraseña')}
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = self.get_base_context()
|
||||||
|
context.update({'form': self.form_class()})
|
||||||
|
return context
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
form = self.form_class(request.POST)
|
||||||
|
|
||||||
|
if form.is_valid():
|
||||||
|
opts = {
|
||||||
|
'use_https': request.is_secure(),
|
||||||
|
'from_email': getattr(settings, 'DEFAULT_FROM_EMAIL'),
|
||||||
|
'request': request,
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.update(self.get_email_options())
|
||||||
|
form.save(**opts)
|
||||||
|
return redirect(self.redirect_to)
|
||||||
|
|
||||||
|
context = self.get_base_context()
|
||||||
|
context.update({'form': form})
|
||||||
|
|
||||||
|
return render(request, self.template_name, context)
|
||||||
|
|
||||||
|
|
||||||
|
class ResetPasswordEmailSent(TemplateView):
|
||||||
|
template_name = 'users/reset_password_email_sent.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
settings = WebSettings.load()
|
||||||
|
|
||||||
|
return {'title': settings.web_title, 'description': settings.web_description}
|
||||||
|
|
||||||
|
|
||||||
|
class ResetPasswordConfirmView(TemplateView):
|
||||||
|
template_name = 'users/reset_password_confirm.html'
|
||||||
|
form_class = SetPasswordForm
|
||||||
|
redirect_to = 'users:login'
|
||||||
|
token_generator = default_token_generator
|
||||||
|
|
||||||
|
def get_user(self):
|
||||||
|
try:
|
||||||
|
uidb64 = self.kwargs.get('uidb64')
|
||||||
|
uid = urlsafe_base64_decode(uidb64).decode()
|
||||||
|
user = User.objects.get(pk=uid)
|
||||||
|
except (TypeError, ValueError, OverflowError, User.DoesNotExist, ValidationError):
|
||||||
|
user = None
|
||||||
|
return user
|
||||||
|
|
||||||
|
def generate_new_token_for_user(self, user):
|
||||||
|
return self.token_generator.make_token(user)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
user = self.get_user()
|
||||||
|
valid_token = self.check_token(user)
|
||||||
|
new_token = self.generate_new_token_for_user(user)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'title': WebSettings.load().web_title,
|
||||||
|
'description': _('Establecer nueva contraseña'),
|
||||||
|
'form': self.form_class(user, {'token': new_token}),
|
||||||
|
'valid_token': valid_token,
|
||||||
|
'new_token': new_token,
|
||||||
|
}
|
||||||
|
|
||||||
|
def check_token(self, user):
|
||||||
|
token = self.kwargs.get('token')
|
||||||
|
valid_token = self.token_generator.check_token(user, token)
|
||||||
|
return valid_token
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
user = self.get_user()
|
||||||
|
form = self.form_class(user, request.POST)
|
||||||
|
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
return redirect(self.redirect_to)
|
||||||
|
return render(request, self.template_name, {})
|
||||||
|
|
||||||
|
|
||||||
|
class MyAccountView(TemplateView):
|
||||||
|
template_name = 'users/user_details.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
addresses = CustomerAddress.objects.filter(user=self.request.user)
|
||||||
|
web_settings = WebSettings.load()
|
||||||
|
return {
|
||||||
|
'title': f'{web_settings.web_title} - Mi cuenta',
|
||||||
|
'description': f'{web_settings.web_title} - Mi cuenta',
|
||||||
|
'customer_addresses': addresses,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
login = LoginView.as_view()
|
||||||
|
logout = LogoutView.as_view()
|
||||||
|
register = RegisterView.as_view()
|
||||||
|
reset_password = ResetPasswordView.as_view()
|
||||||
|
|
||||||
|
reset_password_confirm = ResetPasswordConfirmView.as_view()
|
||||||
|
reset_password_email_sent = ResetPasswordEmailSent.as_view()
|
||||||
|
|
||||||
|
my_account = MyAccountView.as_view()
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ class PaginatedQuerysetMixin:
|
|||||||
class StylingMixin:
|
class StylingMixin:
|
||||||
placeholder_for_field = {}
|
placeholder_for_field = {}
|
||||||
styled_fields = []
|
styled_fields = []
|
||||||
classes = {'input-text'}
|
classes = {'input w-full'}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
styles.css
|
main.css
|
||||||
|
tailwindcss
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
@layer components {
|
|
||||||
.card {
|
|
||||||
@apply rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link {
|
|
||||||
@apply text-lg font-semibold leading-tight text-gray-900 hover:underline dark:text-white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-grid {
|
|
||||||
@apply mb-4 grid gap-4 sm:grid-cols-2 md:mb-8 lg:grid-cols-3 xl:grid-cols-4 3xl:grid-cols-5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-gray {
|
|
||||||
@apply rounded-lg border border-gray-200 bg-white px-5 py-2.5 text-sm font-medium text-gray-900
|
|
||||||
hover:bg-gray-100 hover:text-primary-700 focus:z-10 focus:outline-none focus:ring-4
|
|
||||||
focus:ring-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700
|
|
||||||
dark:hover:text-white dark:focus:ring-gray-700 cursor-pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page {
|
|
||||||
@apply flex justify-center items-center text-lg text-gray-900 dark:text-gray-400 mt-4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-bg {
|
|
||||||
@apply bg-white dark:bg-gray-800 antialiased;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-content {
|
|
||||||
@apply max-w-screen-xl px-4 mx-auto 2xl:px-0 py-4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-align {
|
|
||||||
@apply flex items-center justify-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-categories {
|
|
||||||
@apply hidden lg:flex items-center justify-start gap-6 md:gap-8 py-3 sm:justify-center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-web-title {
|
|
||||||
@apply text-xl font-semibold text-gray-900 dark:text-white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-title {
|
|
||||||
@apply flex items-center space-x-8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-category-link {
|
|
||||||
@apply flex text-sm font-medium text-gray-900 hover:text-primary-700 dark:text-white dark:hover:text-primary-500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-dropdown-menu {
|
|
||||||
@apply bg-gray-50 dark:bg-gray-700 dark:border-gray-600 border border-gray-200 rounded-lg py-3 px-4 mt-4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-dropdown-menu-list {
|
|
||||||
@apply text-gray-900 dark:text-white text-sm font-medium dark:text-white space-y-3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-dropdown-menu-list-items {
|
|
||||||
@apply text-gray-900 dark:text-white text-sm font-medium dark:text-white space-y-3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-dropdown-menu-title {
|
|
||||||
@apply hover:text-primary-700 dark:hover:text-primary-500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
@apply flex text-gray-900 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none rounded-lg text-sm p-4 cursor-pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-button {
|
|
||||||
@apply inline-flex items-center rounded-lg justify-center p-4 hover:bg-gray-100 dark:hover:bg-gray-700 text-sm font-medium leading-none text-gray-900 dark:text-white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cart-navbar-floating {
|
|
||||||
@apply absolute top-12 z-10 w-75 divide-y divide-gray-100 overflow-hidden overflow-y-auto rounded-lg bg-white antialiased shadow dark:divide-gray-600 dark:bg-gray-700 right-0 p-4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-primary {
|
|
||||||
@apply w-full flex justify-center rounded-lg bg-primary-700 px-5 py-2.5
|
|
||||||
text-sm font-medium text-white hover:bg-primary-800 focus:outline-none focus:ring-4
|
|
||||||
focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800
|
|
||||||
content-center items-center cursor-pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-number {
|
|
||||||
@apply bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600
|
|
||||||
focus:border-primary-600 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400
|
|
||||||
dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500 mr-4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-text {
|
|
||||||
@apply my-2 bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600
|
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-checkbox {
|
|
||||||
@apply my-2 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-primary-300
|
|
||||||
dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-primary-600 dark:ring-offset-gray-800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input {
|
|
||||||
@apply block w-full p-2 pl-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.txt-2xl {
|
|
||||||
@apply text-2xl font-extrabold leading-tight text-gray-900 dark:text-white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,36 +0,0 @@
|
|||||||
@import "tailwindcss";
|
|
||||||
@import "./components.css";
|
|
||||||
|
|
||||||
|
|
||||||
@theme {
|
|
||||||
--font-display: "Satoshi", "sans-serif";
|
|
||||||
--breakpoint-3xl: 1920px;
|
|
||||||
|
|
||||||
--ease-fluid: cubic-bezier(0.3, 0, 0, 1);
|
|
||||||
--ease-snappy: cubic-bezier(0.2, 0, 0, 1); /* ... */
|
|
||||||
--color-primary-50: #fff1f2;
|
|
||||||
--color-primary-100: #ffe4e6;
|
|
||||||
--color-primary-200: #fecdd3;
|
|
||||||
--color-primary-300: #fda4af;
|
|
||||||
--color-primary-400: #fb7185;
|
|
||||||
--color-primary-500: #f43f5e;
|
|
||||||
--color-primary-600: #e11d48;
|
|
||||||
--color-primary-700: #be123c;
|
|
||||||
--color-primary-800: #9f1239;
|
|
||||||
--color-primary-900: #881337;
|
|
||||||
--color-primary-950: #4c0519;
|
|
||||||
|
|
||||||
--color-gray-50: #fafafa;
|
|
||||||
--color-gray-100: #f4f4f5;
|
|
||||||
--color-gray-200: #e4e4e7;
|
|
||||||
--color-gray-300: #d4d4d8;
|
|
||||||
--color-gray-400: #a1a1aa;
|
|
||||||
--color-gray-500: #71717a;
|
|
||||||
--color-gray-600: #52525b;
|
|
||||||
--color-gray-700: #3f3f46;
|
|
||||||
--color-gray-800: #27272a;
|
|
||||||
--color-gray-900: #18181b;
|
|
||||||
--color-gray-950: #09090b;
|
|
||||||
}
|
|
||||||
|
|
||||||
@variant dark (&:where(.dark, .dark *));
|
|
||||||
@@ -0,0 +1,407 @@
|
|||||||
|
/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */
|
||||||
|
@layer theme, base, components, utilities;
|
||||||
|
@layer theme {
|
||||||
|
:root, :host {
|
||||||
|
--font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||||
|
'Noto Color Emoji';
|
||||||
|
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
||||||
|
monospace;
|
||||||
|
--default-font-family: var(--font-sans);
|
||||||
|
--default-mono-font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
*, ::after, ::before, ::backdrop, ::file-selector-button {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0 solid;
|
||||||
|
}
|
||||||
|
html, :host {
|
||||||
|
line-height: 1.5;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
tab-size: 4;
|
||||||
|
font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji');
|
||||||
|
font-feature-settings: var(--default-font-feature-settings, normal);
|
||||||
|
font-variation-settings: var(--default-font-variation-settings, normal);
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
height: 0;
|
||||||
|
color: inherit;
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
abbr:where([title]) {
|
||||||
|
-webkit-text-decoration: underline dotted;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
-webkit-text-decoration: inherit;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
b, strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
code, kbd, samp, pre {
|
||||||
|
font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace);
|
||||||
|
font-feature-settings: var(--default-mono-font-feature-settings, normal);
|
||||||
|
font-variation-settings: var(--default-mono-font-variation-settings, normal);
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
sub, sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
text-indent: 0;
|
||||||
|
border-color: inherit;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
:-moz-focusring {
|
||||||
|
outline: auto;
|
||||||
|
}
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
ol, ul, menu {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
img, svg, video, canvas, audio, iframe, embed, object {
|
||||||
|
display: block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
img, video {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
button, input, select, optgroup, textarea, ::file-selector-button {
|
||||||
|
font: inherit;
|
||||||
|
font-feature-settings: inherit;
|
||||||
|
font-variation-settings: inherit;
|
||||||
|
letter-spacing: inherit;
|
||||||
|
color: inherit;
|
||||||
|
border-radius: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
:where(select:is([multiple], [size])) optgroup {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
:where(select:is([multiple], [size])) optgroup option {
|
||||||
|
padding-inline-start: 20px;
|
||||||
|
}
|
||||||
|
::file-selector-button {
|
||||||
|
margin-inline-end: 4px;
|
||||||
|
}
|
||||||
|
::placeholder {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
|
||||||
|
::placeholder {
|
||||||
|
color: currentcolor;
|
||||||
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
|
color: color-mix(in oklab, currentcolor 50%, transparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
::-webkit-date-and-time-value {
|
||||||
|
min-height: 1lh;
|
||||||
|
text-align: inherit;
|
||||||
|
}
|
||||||
|
::-webkit-datetime-edit {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
::-webkit-datetime-edit-fields-wrapper {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
|
||||||
|
padding-block: 0;
|
||||||
|
}
|
||||||
|
::-webkit-calendar-picker-indicator {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
:-moz-ui-invalid {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
button, input:where([type='button'], [type='reset'], [type='submit']), ::file-selector-button {
|
||||||
|
appearance: button;
|
||||||
|
}
|
||||||
|
::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
[hidden]:where(:not([hidden='until-found'])) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer utilities;
|
||||||
|
@layer base {
|
||||||
|
:where(:root),:root:has(input.theme-controller[value=light]:checked),[data-theme=light] {
|
||||||
|
color-scheme: light;
|
||||||
|
--color-base-100: oklch(100% 0 0);
|
||||||
|
--color-base-200: oklch(98% 0 0);
|
||||||
|
--color-base-300: oklch(95% 0 0);
|
||||||
|
--color-base-content: oklch(21% 0.006 285.885);
|
||||||
|
--color-primary: oklch(45% 0.24 277.023);
|
||||||
|
--color-primary-content: oklch(93% 0.034 272.788);
|
||||||
|
--color-secondary: oklch(65% 0.241 354.308);
|
||||||
|
--color-secondary-content: oklch(94% 0.028 342.258);
|
||||||
|
--color-accent: oklch(77% 0.152 181.912);
|
||||||
|
--color-accent-content: oklch(38% 0.063 188.416);
|
||||||
|
--color-neutral: oklch(14% 0.005 285.823);
|
||||||
|
--color-neutral-content: oklch(92% 0.004 286.32);
|
||||||
|
--color-info: oklch(74% 0.16 232.661);
|
||||||
|
--color-info-content: oklch(29% 0.066 243.157);
|
||||||
|
--color-success: oklch(76% 0.177 163.223);
|
||||||
|
--color-success-content: oklch(37% 0.077 168.94);
|
||||||
|
--color-warning: oklch(82% 0.189 84.429);
|
||||||
|
--color-warning-content: oklch(41% 0.112 45.904);
|
||||||
|
--color-error: oklch(71% 0.194 13.428);
|
||||||
|
--color-error-content: oklch(27% 0.105 12.094);
|
||||||
|
--radius-selector: 0.5rem;
|
||||||
|
--radius-field: 0.25rem;
|
||||||
|
--radius-box: 0.5rem;
|
||||||
|
--size-selector: 0.25rem;
|
||||||
|
--size-field: 0.25rem;
|
||||||
|
--border: 1px;
|
||||||
|
--depth: 1;
|
||||||
|
--noise: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root:not([data-theme]) {
|
||||||
|
color-scheme: dark;
|
||||||
|
--color-base-100: oklch(25.33% 0.016 252.42);
|
||||||
|
--color-base-200: oklch(23.26% 0.014 253.1);
|
||||||
|
--color-base-300: oklch(21.15% 0.012 254.09);
|
||||||
|
--color-base-content: oklch(97.807% 0.029 256.847);
|
||||||
|
--color-primary: oklch(58% 0.233 277.117);
|
||||||
|
--color-primary-content: oklch(96% 0.018 272.314);
|
||||||
|
--color-secondary: oklch(65% 0.241 354.308);
|
||||||
|
--color-secondary-content: oklch(94% 0.028 342.258);
|
||||||
|
--color-accent: oklch(77% 0.152 181.912);
|
||||||
|
--color-accent-content: oklch(38% 0.063 188.416);
|
||||||
|
--color-neutral: oklch(14% 0.005 285.823);
|
||||||
|
--color-neutral-content: oklch(92% 0.004 286.32);
|
||||||
|
--color-info: oklch(74% 0.16 232.661);
|
||||||
|
--color-info-content: oklch(29% 0.066 243.157);
|
||||||
|
--color-success: oklch(76% 0.177 163.223);
|
||||||
|
--color-success-content: oklch(37% 0.077 168.94);
|
||||||
|
--color-warning: oklch(82% 0.189 84.429);
|
||||||
|
--color-warning-content: oklch(41% 0.112 45.904);
|
||||||
|
--color-error: oklch(71% 0.194 13.428);
|
||||||
|
--color-error-content: oklch(27% 0.105 12.094);
|
||||||
|
--radius-selector: 0.5rem;
|
||||||
|
--radius-field: 0.25rem;
|
||||||
|
--radius-box: 0.5rem;
|
||||||
|
--size-selector: 0.25rem;
|
||||||
|
--size-field: 0.25rem;
|
||||||
|
--border: 1px;
|
||||||
|
--depth: 1;
|
||||||
|
--noise: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
:root:has(input.theme-controller[value=light]:checked),[data-theme=light] {
|
||||||
|
color-scheme: light;
|
||||||
|
--color-base-100: oklch(100% 0 0);
|
||||||
|
--color-base-200: oklch(98% 0 0);
|
||||||
|
--color-base-300: oklch(95% 0 0);
|
||||||
|
--color-base-content: oklch(21% 0.006 285.885);
|
||||||
|
--color-primary: oklch(45% 0.24 277.023);
|
||||||
|
--color-primary-content: oklch(93% 0.034 272.788);
|
||||||
|
--color-secondary: oklch(65% 0.241 354.308);
|
||||||
|
--color-secondary-content: oklch(94% 0.028 342.258);
|
||||||
|
--color-accent: oklch(77% 0.152 181.912);
|
||||||
|
--color-accent-content: oklch(38% 0.063 188.416);
|
||||||
|
--color-neutral: oklch(14% 0.005 285.823);
|
||||||
|
--color-neutral-content: oklch(92% 0.004 286.32);
|
||||||
|
--color-info: oklch(74% 0.16 232.661);
|
||||||
|
--color-info-content: oklch(29% 0.066 243.157);
|
||||||
|
--color-success: oklch(76% 0.177 163.223);
|
||||||
|
--color-success-content: oklch(37% 0.077 168.94);
|
||||||
|
--color-warning: oklch(82% 0.189 84.429);
|
||||||
|
--color-warning-content: oklch(41% 0.112 45.904);
|
||||||
|
--color-error: oklch(71% 0.194 13.428);
|
||||||
|
--color-error-content: oklch(27% 0.105 12.094);
|
||||||
|
--radius-selector: 0.5rem;
|
||||||
|
--radius-field: 0.25rem;
|
||||||
|
--radius-box: 0.5rem;
|
||||||
|
--size-selector: 0.25rem;
|
||||||
|
--size-field: 0.25rem;
|
||||||
|
--border: 1px;
|
||||||
|
--depth: 1;
|
||||||
|
--noise: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
:root:has(input.theme-controller[value=dark]:checked),[data-theme=dark] {
|
||||||
|
color-scheme: dark;
|
||||||
|
--color-base-100: oklch(25.33% 0.016 252.42);
|
||||||
|
--color-base-200: oklch(23.26% 0.014 253.1);
|
||||||
|
--color-base-300: oklch(21.15% 0.012 254.09);
|
||||||
|
--color-base-content: oklch(97.807% 0.029 256.847);
|
||||||
|
--color-primary: oklch(58% 0.233 277.117);
|
||||||
|
--color-primary-content: oklch(96% 0.018 272.314);
|
||||||
|
--color-secondary: oklch(65% 0.241 354.308);
|
||||||
|
--color-secondary-content: oklch(94% 0.028 342.258);
|
||||||
|
--color-accent: oklch(77% 0.152 181.912);
|
||||||
|
--color-accent-content: oklch(38% 0.063 188.416);
|
||||||
|
--color-neutral: oklch(14% 0.005 285.823);
|
||||||
|
--color-neutral-content: oklch(92% 0.004 286.32);
|
||||||
|
--color-info: oklch(74% 0.16 232.661);
|
||||||
|
--color-info-content: oklch(29% 0.066 243.157);
|
||||||
|
--color-success: oklch(76% 0.177 163.223);
|
||||||
|
--color-success-content: oklch(37% 0.077 168.94);
|
||||||
|
--color-warning: oklch(82% 0.189 84.429);
|
||||||
|
--color-warning-content: oklch(41% 0.112 45.904);
|
||||||
|
--color-error: oklch(71% 0.194 13.428);
|
||||||
|
--color-error-content: oklch(27% 0.105 12.094);
|
||||||
|
--radius-selector: 0.5rem;
|
||||||
|
--radius-field: 0.25rem;
|
||||||
|
--radius-box: 0.5rem;
|
||||||
|
--size-selector: 0.25rem;
|
||||||
|
--size-field: 0.25rem;
|
||||||
|
--border: 1px;
|
||||||
|
--depth: 1;
|
||||||
|
--noise: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--fx-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.34' numOctaves='4' stitchTiles='stitch'%3E%3C/feTurbulence%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23a)' opacity='0.2'%3E%3C/rect%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
scrollbar-color: currentColor #0000;
|
||||||
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
|
scrollbar-color: color-mix(in oklch, currentColor 35%, #0000) #0000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
@property --radialprogress {
|
||||||
|
syntax: "<percentage>";
|
||||||
|
inherits: true;
|
||||||
|
initial-value: 0%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
:root:not(span) {
|
||||||
|
overflow: var(--page-overflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
background: var(--page-scroll-bg, var(--root-bg));
|
||||||
|
--page-scroll-bg-on: linear-gradient(var(--root-bg, #0000), var(--root-bg, #0000))
|
||||||
|
var(--root-bg, #0000);
|
||||||
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
|
--page-scroll-bg-on: linear-gradient(var(--root-bg, #0000), var(--root-bg, #0000))
|
||||||
|
color-mix(in srgb, var(--root-bg, #0000), oklch(0% 0 0) calc(var(--page-has-backdrop, 0) * 40%));
|
||||||
|
}
|
||||||
|
--page-scroll-transition-on: background-color 0.3s ease-out;
|
||||||
|
transition: var(--page-scroll-transition);
|
||||||
|
scrollbar-gutter: var(--page-scroll-gutter, unset);
|
||||||
|
scrollbar-gutter: if(style(--page-has-scroll: 1): var(--page-scroll-gutter, unset) ; else: unset);
|
||||||
|
}
|
||||||
|
@keyframes set-page-has-scroll {
|
||||||
|
0%, to {
|
||||||
|
--page-has-scroll: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
:root, [data-theme] {
|
||||||
|
background: var(--page-scroll-bg, var(--root-bg));
|
||||||
|
color: var(--color-base-content);
|
||||||
|
}
|
||||||
|
:where(:root, [data-theme]) {
|
||||||
|
--root-bg: var(--color-base-100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes rating {
|
||||||
|
0%, 40% {
|
||||||
|
scale: 1.1;
|
||||||
|
filter: brightness(1.05) contrast(1.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes dropdown {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes radio {
|
||||||
|
0% {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes toast {
|
||||||
|
0% {
|
||||||
|
scale: 0.9;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
scale: 1;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes rotator {
|
||||||
|
89.9999%, 100% {
|
||||||
|
--first-item-position: 0 0%;
|
||||||
|
}
|
||||||
|
90%, 99.9999% {
|
||||||
|
--first-item-position: 0 calc(var(--items) * 100%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
translate: 0 -100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes skeleton {
|
||||||
|
0% {
|
||||||
|
background-position: 150%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: -50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes menu {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes progress {
|
||||||
|
50% {
|
||||||
|
background-position-x: -115%;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,14 +4,14 @@ const darkIcon = document.getElementById('theme-toggle-dark-icon')
|
|||||||
const lightIcon = document.getElementById('theme-toggle-light-icon')
|
const lightIcon = document.getElementById('theme-toggle-light-icon')
|
||||||
|
|
||||||
if (currentTheme === 'dark') {
|
if (currentTheme === 'dark') {
|
||||||
document.documentElement.classList.add('dark')
|
document.documentElement.setAttribute('data-theme', 'forest')
|
||||||
|
|
||||||
if (darkIcon !== null && lightIcon !== null) {
|
if (darkIcon !== null && lightIcon !== null) {
|
||||||
darkIcon.classList.add('hidden')
|
darkIcon.classList.add('hidden')
|
||||||
lightIcon.classList.remove('hidden')
|
lightIcon.classList.remove('hidden')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.remove('dark')
|
document.documentElement.setAttribute('data-theme', 'cupcake')
|
||||||
|
|
||||||
if (darkIcon !== null && lightIcon !== null) {
|
if (darkIcon !== null && lightIcon !== null) {
|
||||||
darkIcon.classList.remove('hidden')
|
darkIcon.classList.remove('hidden')
|
||||||
@@ -24,12 +24,12 @@ function switchTheme() {
|
|||||||
const theme = localStorage.getItem('theme')
|
const theme = localStorage.getItem('theme')
|
||||||
|
|
||||||
if (theme === 'dark') {
|
if (theme === 'dark') {
|
||||||
document.documentElement.classList.remove('dark')
|
document.documentElement.setAttribute('data-theme', 'cupcake')
|
||||||
localStorage.setItem('theme', 'light')
|
localStorage.setItem('theme', 'light')
|
||||||
darkIcon.classList.remove('hidden')
|
darkIcon.classList.remove('hidden')
|
||||||
lightIcon.classList.add('hidden')
|
lightIcon.classList.add('hidden')
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.add('dark')
|
document.documentElement.setAttribute('data-theme', 'forest')
|
||||||
localStorage.setItem('theme', 'dark')
|
localStorage.setItem('theme', 'dark')
|
||||||
lightIcon.classList.remove('hidden')
|
lightIcon.classList.remove('hidden')
|
||||||
darkIcon.classList.add('hidden')
|
darkIcon.classList.add('hidden')
|
||||||
|
|||||||
@@ -4,9 +4,8 @@
|
|||||||
<input type="hidden" name="product" value="{{ product.pk }}">
|
<input type="hidden" name="product" value="{{ product.pk }}">
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<input class="input-number"
|
<input class="input" id="quantity" aria-label="quantity" type="number" min="1" max="10" name="quantity" value="1">
|
||||||
id="quantity" aria-label="quantity" type="number" min="1" max="10" name="quantity" value="1">
|
<button class="btn btn-primary"
|
||||||
<button class="button-primary"
|
|
||||||
>
|
>
|
||||||
{% include 'components/icons/add_cart.svg' %}
|
{% include 'components/icons/add_cart.svg' %}
|
||||||
{% translate 'Añadir al carrito' %}
|
{% translate 'Añadir al carrito' %}
|
||||||
|
|||||||
@@ -1,30 +1,28 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<section class="bg-white py-2 antialiased dark:bg-gray-900 md:py-8">
|
<section class=" py-2 antialiased md:py-8">
|
||||||
<form action="{% url 'web:cart_detail' %}" method="post">
|
<form action="{% url 'web:cart_detail' %}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="mx-auto max-w-screen-xl px-4 2xl:px-0">
|
<div class="mx-auto max-w-screen-xl px-4 2xl:px-0">
|
||||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">{% translate 'Carrito' %}</h2>
|
<h2 class="text-xl font-semibold sm:text-2xl">{% translate 'Carrito' %}</h2>
|
||||||
|
|
||||||
<div class="mt-4 sm:mt-6 md:gap-6 lg:flex lg:items-start xl:gap-8">
|
<div class="mt-4 sm:mt-6 md:gap-6 lg:flex lg:items-start xl:gap-8">
|
||||||
<div class="mx-auto w-full flex-none lg:max-w-2xl xl:max-w-4xl">
|
<div class="mx-auto w-full flex-none lg:max-w-2xl xl:max-w-4xl">
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
|
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
<div class="rounded-lg border border-gray-200 bg-white p-4 shadow-sm
|
<div class="rounded-lg p-4 shadow-sm md:p-6">
|
||||||
dark:border-gray-700 dark:bg-gray-800 md:p-6">
|
|
||||||
<div class="space-y-4 flex items-center justify-between gap-6 space-y-0">
|
<div class="space-y-4 flex items-center justify-between gap-6 space-y-0">
|
||||||
<a href="{% url 'web:product_detail' pk=item.product.pk slug=item.product.slug %}"
|
<a href="{% url 'web:product_detail' pk=item.product.pk slug=item.product.slug %}"
|
||||||
class="shrink-0 md:order-1">
|
class="shrink-0 md:order-1">
|
||||||
<img class="h-20 w-20 dark:hidden" src="{{ item.product.images.all.0.s.url }}"
|
<img class="h-20 w-20" src="{{ item.product.images.all.0.s.url }}"
|
||||||
alt="{{ item.product.name }}"/>
|
alt="{{ item.product.name }}"/>
|
||||||
<img class="hidden h-20 w-20 dark:block" src="{{ item.product.images.all.0.s_dark.url }}"
|
<img class="hidden h-20 w-20" src="{{ item.product.images.all.0.s_dark.url }}"
|
||||||
alt="{{ item.product.name }}"/>
|
alt="{{ item.product.name }}"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
<div class="w-full min-w-0 flex-1 space-y-4 md:order-2 md:max-w-md">
|
<div class="w-full min-w-0 flex-1 space-y-4 md:order-2 md:max-w-md">
|
||||||
<a href="{% url 'web:product_detail' pk=item.product.pk slug=item.product.slug %}"
|
<a href="{% url 'web:product_detail' pk=item.product.pk slug=item.product.slug %}"
|
||||||
class="text-base font-medium text-gray-900 hover:underline dark:text-white"
|
class="text-base font-medium hover:underline "
|
||||||
>
|
>
|
||||||
{{ item.product.name }}
|
{{ item.product.name }}
|
||||||
</a>
|
</a>
|
||||||
@@ -35,7 +33,7 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="inline-flex items-center text-sm font-medium text-red-700 hover:underline dark:text-red-400 cursor-pointer"
|
class="inline-flex items-center text-sm font-medium text-red-700 hover:underline cursor-pointer"
|
||||||
>
|
>
|
||||||
{% include 'components/icons/x.svg' %}
|
{% include 'components/icons/x.svg' %}
|
||||||
{% translate 'Quitar' %}
|
{% translate 'Quitar' %}
|
||||||
@@ -46,52 +44,46 @@
|
|||||||
<label for="counter-input" class="sr-only">{% translate 'Cantidad' %}</label>
|
<label for="counter-input" class="sr-only">{% translate 'Cantidad' %}</label>
|
||||||
<div class="flex items-center justify-between md:order-3 md:justify-end">
|
<div class="flex items-center justify-between md:order-3 md:justify-end">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span class="w-10 shrink-0 border-0 bg-transparent text-center text-sm font-medium
|
<span class="w-10 shrink-0 text-center text-sm font-medium focus:outline-none focus:ring-0">
|
||||||
text-gray-900 focus:outline-none focus:ring-0 dark:text-white"
|
|
||||||
>
|
|
||||||
{{ item.quantity }}x
|
{{ item.quantity }}x
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-end md:order-4 md:w-32">
|
<div class="text-end md:order-4 md:w-32">
|
||||||
<p class="text-base font-bold text-gray-900 dark:text-white">
|
<p class="text-base font-bold ">
|
||||||
{{ item.product.price.price_with_tax }}€
|
{{ item.product.price.price_with_tax }}€
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if items.count == 0 %}
|
{% if items.count == 0 %}
|
||||||
<p class="text-base font-normal text-gray-500 dark:text-gray-400">
|
<p class="text-base font-normal ">
|
||||||
{% translate 'No hay nada en el carrito...' %}
|
{% translate 'No hay nada en el carrito...' %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="{% url 'web:index' %}" title=""
|
<a href="{% url 'web:index' %}" title=""
|
||||||
class="inline-flex items-center gap-2 text-sm font-medium text-primary-700 underline hover:no-underline dark:text-primary-500">
|
class="inline-flex items-center gap-2 text-sm font-medium text-primary-700 underline hover:no-underline ">
|
||||||
{% translate 'Volver a inicio' %}
|
{% translate 'Volver a inicio' %}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">
|
<h2 class="text-xl font-semibold sm:text-2xl">
|
||||||
{% translate 'Dirección de envío' %}
|
{% translate 'Dirección de envío' %}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<section class="p-4 rounded-lg border border-gray-200 dark:border-gray-600">
|
<section class="p-4 rounded-lg">
|
||||||
|
|
||||||
<div class="grid gap-4 sm:grid-cols-2 sm:gap-6 my-2">
|
<div class="grid gap-4 sm:grid-cols-2 sm:gap-6 my-2">
|
||||||
{% if user.is_anonymous %}
|
{% if user.is_anonymous %}
|
||||||
<div class="sm:col-span-2">
|
<div class="sm:col-span-2">
|
||||||
<label for="email"
|
<label for="email"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{% translate 'E-Mail' %}</label>
|
{% translate 'E-Mail' %}</label>
|
||||||
<input type="text" name="email" id="email"
|
<input type="text" name="email" id="email"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'E-Mail' %}"
|
placeholder="{% translate 'E-Mail' %}"
|
||||||
value=""
|
value=""
|
||||||
required=""
|
required=""
|
||||||
@@ -102,23 +94,19 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="sm:col-span-2">
|
<div class="sm:col-span-2">
|
||||||
<label for="shipping_address_full_name"
|
<label for="shipping_address_full_name"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{% translate 'Nombre completo' %}</label>
|
{% translate 'Nombre completo' %}</label>
|
||||||
<input type="text" name="shipping_address_full_name" id="shipping_address_full_name"
|
<input type="text" name="shipping_address_full_name" id="shipping_address_full_name"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'Nombre completo' %}"
|
placeholder="{% translate 'Nombre completo' %}"
|
||||||
value="{% if shipping_address %}{{ shipping_address.full_name }}{% endif %}"
|
value="{% if shipping_address %}{{ shipping_address.full_name }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
>
|
>
|
||||||
<label for="shipping_address"
|
<label for="shipping_address"
|
||||||
class="block my-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block my-2 text-sm font-medium ">
|
||||||
{% translate 'Dirección' %}</label>
|
{% translate 'Dirección' %}</label>
|
||||||
<input type="text" name="shipping_address" id="shipping_address"
|
<input type="text" name="shipping_address" id="shipping_address"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'Dirección' %}"
|
placeholder="{% translate 'Dirección' %}"
|
||||||
value="{% if shipping_address %}{{ shipping_address.address }}{% endif %}"
|
value="{% if shipping_address %}{{ shipping_address.address }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
@@ -126,13 +114,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<label for="shipping_address_town"
|
<label for="shipping_address_town"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{% translate 'Localidad' %}
|
{% translate 'Localidad' %}
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="shipping_address_town" id="shipping_address_town"
|
<input type="text" name="shipping_address_town" id="shipping_address_town"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'Localidad' %}"
|
placeholder="{% translate 'Localidad' %}"
|
||||||
value="{% if shipping_address %}{{ shipping_address.address_town }}{% endif %}"
|
value="{% if shipping_address %}{{ shipping_address.address_town }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
@@ -140,13 +126,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<label for="shipping_address_zip"
|
<label for="shipping_address_zip"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{% translate 'Código postal' %}
|
{% translate 'Código postal' %}
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="shipping_address_zip" id="shipping_address_zip"
|
<input type="text" name="shipping_address_zip" id="shipping_address_zip"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'Código postal' %}"
|
placeholder="{% translate 'Código postal' %}"
|
||||||
value="{% if shipping_address %}{{ shipping_address.address_zip }}{% endif %}"
|
value="{% if shipping_address %}{{ shipping_address.address_zip }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
@@ -155,13 +139,11 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="shipping_address_state"
|
<label for="shipping_address_state"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{% translate 'Provincia' %}
|
{% translate 'Provincia' %}
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="shipping_address_state" id="shipping_address_state"
|
<input type="text" name="shipping_address_state" id="shipping_address_state"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'Provincia' %}"
|
placeholder="{% translate 'Provincia' %}"
|
||||||
value="{% if shipping_address %}{{ shipping_address.address_state }}{% endif %}"
|
value="{% if shipping_address %}{{ shipping_address.address_state }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
@@ -169,14 +151,11 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="shipping_address_country"
|
<label for="shipping_address_country" class="block mb-2 text-sm font-medium ">
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
|
||||||
{% translate 'País' %}
|
{% translate 'País' %}
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="shipping_address_country" id="shipping_address_country"
|
<input type="text" name="shipping_address_country" id="shipping_address_country"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'País' %}"
|
placeholder="{% translate 'País' %}"
|
||||||
value="{% if shipping_address %}{{ shipping_address.address_country }}{% endif %}"
|
value="{% if shipping_address %}{{ shipping_address.address_country }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
@@ -186,33 +165,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">
|
<h2 class="text-xl font-semibold sm:text-2xl">
|
||||||
{% translate 'Dirección de facturación' %}
|
{% translate 'Dirección de facturación' %}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<section class="p-4 rounded-lg border border-gray-200 dark:border-gray-600">
|
<section class="p-4 rounded-lg">
|
||||||
|
|
||||||
<div class="grid gap-4 sm:grid-cols-2 sm:gap-6 my-2">
|
<div class="grid gap-4 sm:grid-cols-2 sm:gap-6 my-2">
|
||||||
<div class="sm:col-span-2">
|
<div class="sm:col-span-2">
|
||||||
<label for="billing_address_full_name"
|
<label for="billing_address_full_name"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{% translate 'Nombre completo' %}</label>
|
{% translate 'Nombre completo' %}</label>
|
||||||
<input type="text" name="billing_address_full_name" id="billing_address_full_name"
|
<input type="text" name="billing_address_full_name" id="billing_address_full_name"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'Nombre completo' %}"
|
placeholder="{% translate 'Nombre completo' %}"
|
||||||
value="{% if billing_address %}{{ billing_address.full_name }}{% endif %}"
|
value="{% if billing_address %}{{ billing_address.full_name }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
>
|
>
|
||||||
<label for="billing_address"
|
<label for="billing_address"
|
||||||
class="block my-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block my-2 text-sm font-medium ">
|
||||||
{% translate 'Dirección' %}
|
{% translate 'Dirección' %}
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="billing_address" id="billing_address"
|
<input type="text" name="billing_address" id="billing_address"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'Dirección' %}"
|
placeholder="{% translate 'Dirección' %}"
|
||||||
value="{% if billing_address %}{{ billing_address.address }}{% endif %}"
|
value="{% if billing_address %}{{ billing_address.address }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
@@ -220,13 +195,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<label for="billing_address_town"
|
<label for="billing_address_town"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{% translate 'Localidad' %}
|
{% translate 'Localidad' %}
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="billing_address_town" id="billing_address_town"
|
<input type="text" name="billing_address_town" id="billing_address_town"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'Localidad' %}"
|
placeholder="{% translate 'Localidad' %}"
|
||||||
value="{% if billing_address %}{{ billing_address.address_town }}{% endif %}"
|
value="{% if billing_address %}{{ billing_address.address_town }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
@@ -234,13 +207,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<label for="billing_address_zip"
|
<label for="billing_address_zip"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{% translate 'Código postal' %}
|
{% translate 'Código postal' %}
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="billing_address_zip" id="billing_address_zip"
|
<input type="text" name="billing_address_zip" id="billing_address_zip"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'Código postal' %}"
|
placeholder="{% translate 'Código postal' %}"
|
||||||
value="{% if billing_address %}{{ billing_address.address_zip }}{% endif %}"
|
value="{% if billing_address %}{{ billing_address.address_zip }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
@@ -249,13 +220,11 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="billing_address_state"
|
<label for="billing_address_state"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{% translate 'Provincia' %}
|
{% translate 'Provincia' %}
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="billing_address_state" id="billing_address_state"
|
<input type="text" name="billing_address_state" id="billing_address_state"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'Provincia' %}"
|
placeholder="{% translate 'Provincia' %}"
|
||||||
value="{% if billing_address %}{{ billing_address.address_state }}{% endif %}"
|
value="{% if billing_address %}{{ billing_address.address_state }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
@@ -264,13 +233,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="billing_address_country"
|
<label for="billing_address_country"
|
||||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
class="block mb-2 text-sm font-medium ">
|
||||||
{% translate 'País' %}
|
{% translate 'País' %}
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="billing_address_country" id="billing_address_country"
|
<input type="text" name="billing_address_country" id="billing_address_country"
|
||||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600
|
class="input"
|
||||||
focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
|
|
||||||
dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
||||||
placeholder="{% translate 'País' %}"
|
placeholder="{% translate 'País' %}"
|
||||||
value="{% if billing_address %}{{ billing_address.address_country }}{% endif %}"
|
value="{% if billing_address %}{{ billing_address.address_country }}{% endif %}"
|
||||||
required=""
|
required=""
|
||||||
@@ -281,10 +248,10 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2 class="text-xl mb-4 font-semibold text-gray-900 dark:text-white sm:text-2xl">
|
<h2 class="text-xl mb-4 font-semibold sm:text-2xl">
|
||||||
{% translate 'Opciones de envío' %}
|
{% translate 'Opciones de envío' %}
|
||||||
</h2>
|
</h2>
|
||||||
<article class="rounded-lg border border-gray-200 dark:border-gray-600">
|
<article class="rounded-lg">
|
||||||
|
|
||||||
{% for shipping_method in shipping_methods %}
|
{% for shipping_method in shipping_methods %}
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
@@ -292,27 +259,25 @@
|
|||||||
name="shipping_method"
|
name="shipping_method"
|
||||||
value="{{ shipping_method.pk }}" {% if forloop.first %}checked{% endif %}>
|
value="{{ shipping_method.pk }}" {% if forloop.first %}checked{% endif %}>
|
||||||
<label for="shipping_method_{{ shipping_method.pk }}"
|
<label for="shipping_method_{{ shipping_method.pk }}"
|
||||||
class="text-gray-900 dark:text-white">
|
class=" ">
|
||||||
{{ shipping_method.name }} - {{ shipping_method.shipping_product.price.price_with_tax }}€
|
{{ shipping_method.name }} - {{ shipping_method.shipping_product.price.price_with_tax }}€
|
||||||
</label>
|
</label>
|
||||||
{% if not forloop.last %}
|
{% if not forloop.last %}
|
||||||
</div>
|
</div>
|
||||||
<hr class="h-px mx-4 bg-gray-200 border-0 dark:bg-gray-700"/>
|
<hr class="h-px mx-4"/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Resumen del pedido -->
|
<!-- Resumen del pedido -->
|
||||||
<div class="mx-auto mt-6 max-w-4xl flex-1 space-y-6 lg:mt-0 lg:w-full">
|
<div class="mx-auto mt-6 max-w-4xl flex-1 space-y-6 lg:mt-0 lg:w-full">
|
||||||
<div
|
<div
|
||||||
class="space-y-4 rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-800 sm:p-6">
|
class="space-y-4 rounded-lg p-4 shadow-sm sm:p-6">
|
||||||
<p class="text-xl font-semibold text-gray-900 dark:text-white">
|
<p class="text-xl font-semibold ">
|
||||||
{% translate 'Resumen del pedido' %}
|
{% translate 'Resumen del pedido' %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -320,54 +285,54 @@
|
|||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<dl class="flex items-center justify-between gap-4">
|
<dl class="flex items-center justify-between gap-4">
|
||||||
<dt
|
<dt
|
||||||
class="text-base font-normal text-gray-500 dark:text-gray-400">
|
class="text-base font-normal ">
|
||||||
{% translate 'Base imponible' %}
|
{% translate 'Base imponible' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-base font-medium text-gray-900 dark:text-white">{{ base_total }} €
|
<dd class="text-base font-medium ">{{ base_total }} €
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<dl class="flex items-center justify-between gap-4">
|
<dl class="flex items-center justify-between gap-4">
|
||||||
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">
|
<dt class="text-base font-normal ">
|
||||||
{% translate 'Descuentos' %}
|
{% translate 'Descuentos' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-base font-medium text-green-600">-{{ savings }} €</dd>
|
<dd class="text-base font-medium text-green-600">-{{ savings }} €</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<dl class="flex items-center justify-between gap-4">
|
<dl class="flex items-center justify-between gap-4">
|
||||||
<dt
|
<dt class="text-base font-normal">
|
||||||
class="text-base font-normal text-gray-500 dark:text-gray-400">
|
|
||||||
{% translate 'Gastos de envío' %}
|
{% translate 'Gastos de envío' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-base font-medium text-gray-900 dark:text-white">
|
<dd class="text-base font-medium ">
|
||||||
{{ shipping_cost }} €
|
{{ shipping_cost }} €
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<dl class="flex items-center justify-between gap-4">
|
<dl class="flex items-center justify-between gap-4">
|
||||||
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">
|
<dt class="text-base font-normal ">
|
||||||
{% translate 'Impuestos' %}
|
{% translate 'Impuestos' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-base font-medium text-gray-900 dark:text-white">{{ tax_total }} €
|
<dd class="text-base font-medium ">{{ tax_total }} €
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<dl class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dark:border-gray-700">
|
<dl class="flex items-center justify-between gap-4 pt-2 ">
|
||||||
<dt class="text-base font-bold text-gray-900 dark:text-white">{% translate 'Total' %}
|
<dt class="text-base font-bold ">{% translate 'Total' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-base font-bold text-gray-900 dark:text-white">{{ total }} €</dd>
|
<dd class="text-base font-bold ">{{ total }} €</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="flex w-full items-center justify-center rounded-lg bg-primary-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-primary-800 focus:outline-none focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 cursor-pointer">
|
<button
|
||||||
|
class="flex w-full items-center justify-center rounded-lg px-5 py-2.5 text-sm font-medium text-white hover: focus:outline-none focus:ring-4 focus:ring-primary-300 : :ring-primary-800 cursor-pointer">
|
||||||
{% translate 'Terminar pedido' %}
|
{% translate 'Terminar pedido' %}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="flex items-center justify-center gap-2">
|
<div class="flex items-center justify-center gap-2">
|
||||||
<span class="text-sm font-normal text-gray-500 dark:text-gray-400"> {% translate 'o' %} </span>
|
<span class="text-sm font-normal "> {% translate 'o' %} </span>
|
||||||
<a href="{% url 'web:index' %}" title=""
|
<a href="{% url 'web:index' %}" title=""
|
||||||
class="inline-flex items-center gap-2 text-sm font-medium text-primary-700 underline hover:no-underline dark:text-primary-400">
|
class="inline-flex items-center gap-2 text-sm font-medium text-primary-700 underline hover:no-underline ">
|
||||||
{% translate 'Seguir comprando' %}
|
{% translate 'Seguir comprando' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,30 +16,30 @@
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
{% if cart.items.count == 0 %}
|
{% if cart.items.count == 0 %}
|
||||||
<h2 class="text-sm font-medium text-gray-900 dark:text-white">No hay nada en el carrito</h2>
|
<h2 class="text-sm font-medium ">No hay nada en el carrito</h2>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for cart_item in cart.items.all %}
|
{% for cart_item in cart.items.all %}
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'web:product_detail' pk=cart_item.product.pk slug=cart_item.product.slug %}"
|
<a href="{% url 'web:product_detail' pk=cart_item.product.pk slug=cart_item.product.slug %}"
|
||||||
class="text-sm font-semibold leading-none text-gray-900 dark:text-white hover:underline">
|
class="text-sm font-semibold leading-none hover:underline">
|
||||||
{{ cart_item.product.name }}
|
{{ cart_item.product.name }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="flex items-center justify-between gap-6">
|
<div class="flex items-center justify-between gap-6">
|
||||||
<p
|
<p
|
||||||
class="mt-0.5 truncate text-sm font-normal text-gray-500 dark:text-gray-400">
|
class="mt-0.5 truncate text-sm font-normal ">
|
||||||
{{ cart_item.product.price.price_with_tax }}€
|
{{ cart_item.product.price.price_with_tax }}€
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form hx-post="{% url 'web:delete_cart_item' pk=cart_item.pk %}"
|
<form hx-post="{% url 'web:delete_cart_item' pk=cart_item.pk %}"
|
||||||
hx-swap="none">
|
hx-swap="none">
|
||||||
<span class="mt-0.5 truncate text-sm font-normal text-gray-500 dark:text-gray-400 mr-2">
|
<span class="mt-0.5 truncate text-sm font-normal mr-2">
|
||||||
{% translate 'Cantidad' %}: {{ cart_item.quantity }}
|
{% translate 'Cantidad' %}: {{ cart_item.quantity }}
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
<button data-tooltip-target="tooltipRemoveItem1a" type="submit"
|
<button data-tooltip-target="tooltipRemoveItem1a" type="submit"
|
||||||
class="text-red-600 hover:text-red-700 dark:text-red-500 dark:hover:text-red-600 cursor-pointer"
|
class="text-red-600 hover:text-red-700 :text-red-600 cursor-pointer"
|
||||||
>
|
>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<span class="sr-only">{% translate 'Quitar' %}</span>
|
<span class="sr-only">{% translate 'Quitar' %}</span>
|
||||||
@@ -48,21 +48,21 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div id="tooltipRemoveItem1a" role="tooltip"
|
<div id="tooltipRemoveItem1a" role="tooltip"
|
||||||
class="tooltip invisible absolute z-10 inline-block rounded-lg bg-gray-900 px-3 py-2 text-sm font-medium
|
class="tooltip invisible absolute z-10 inline-block rounded-lg px-3 py-2 text-sm font-medium
|
||||||
text-white opacity-0 shadow-sm transition-opacity duration-300 dark:bg-gray-700"
|
text-white opacity-0 shadow-sm transition-opacity duration-300 "
|
||||||
>
|
>
|
||||||
{% translate 'Quitar del carrito' %}
|
{% translate 'Quitar del carrito' %}
|
||||||
<div class="tooltip-arrow" data-popper-arrow></div>
|
<div class="tooltip-arrow" data-popper-arrow></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr class="h-px mx-4 my-2 bg-gray-200 border-0 dark:bg-gray-700" />
|
<hr class="h-px mx-4 my-2 " />
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if cart.items.count > 0 %}
|
{% if cart.items.count > 0 %}
|
||||||
<a href="{% url 'web:cart_detail' %}"
|
<a href="{% url 'web:cart_detail' %}"
|
||||||
class="button-primary"
|
class="btn btn-primary"
|
||||||
role="button"> {% translate 'Ver carrito' %}
|
role="button"> {% translate 'Ver carrito' %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label for="{{ field.id_for_label }}"
|
<label for="{{ field.id_for_label }}"
|
||||||
class="inline-block text-sm font-medium text-gray-900 dark:text-white ml-2">
|
class="inline-block text-sm font-medium ml-2">
|
||||||
{{ field.label }}
|
{{ field.label }}
|
||||||
</label>
|
</label>
|
||||||
{{ field }}
|
{{ field }}
|
||||||
@@ -13,17 +13,17 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% for k, error in form.errors.items %}
|
{% for k, error in form.errors.items %}
|
||||||
<span class="flex justify-center mb-2 text-sm font-medium text-red-900 dark:text-red-400">{{ error }}</span>
|
<span class="flex justify-center mb-2 text-sm font-medium text-red-900 ">{{ error }}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if success_message %}
|
{% if success_message %}
|
||||||
<span class="flex justify-center mb-2 text-sm font-medium text-red-900 dark:text-red-400">{{ success_message }}</span>
|
<span class="flex justify-center mb-2 text-sm font-medium text-red-900 ">{{ success_message }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<footer class="flex justify-end">
|
<footer class="flex justify-end">
|
||||||
<button class="text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none
|
<button class="text-white hover: focus:ring-4 focus:outline-none
|
||||||
focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600
|
focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center
|
||||||
dark:hover:bg-primary-700 dark:focus:ring-primary-800 cursor-pointer"
|
: :ring-primary-800 cursor-pointer"
|
||||||
>
|
>
|
||||||
{{ save_button_text }}
|
{{ save_button_text }}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,102 +1,26 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<nav class="navbar-bg">
|
<nav class="navbar bg-base-100 shadow-sm">
|
||||||
<!-- Left side -->
|
<div class="flex-1">
|
||||||
<div class="navbar-content">
|
|
||||||
<div class="navbar-align">
|
|
||||||
|
|
||||||
<!-- Title -->
|
<a href="{% url 'web:index' %}" class="flex text-xl">
|
||||||
<div class="navbar-title">
|
<img class="mr-4" src="{{ logo }}" alt="{{ web_title }} logo">
|
||||||
<div class="shrink-0">
|
{{ web_title }}
|
||||||
<a class="flex flex-row items-center" href="{% url 'web:index' %}">
|
|
||||||
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="{{ web_title }} logo">
|
|
||||||
<h1 class="navbar-web-title">{{ web_title }}</h1>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Categories -->
|
<div class="flex gap-2">
|
||||||
<ul class="navbar-categories">
|
<input type="text" placeholder="{% trans 'Buscar...' %}" class="input input-bordered w-24 md:w-auto"/>
|
||||||
<li>
|
|
||||||
<a href="{% url 'web:index' %}" title=""
|
|
||||||
class="navbar-category-link">
|
|
||||||
{% translate 'Inicio' %}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% for category in navbar_categories %}
|
|
||||||
<li class="shrink-0">
|
|
||||||
<a href="{% url 'web:category_view' slug=category.slug %}" title=""
|
|
||||||
class="navbar-category-link">
|
|
||||||
{{ category.name }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Right side -->
|
{% include 'components/generic/theme-switch.html' %}
|
||||||
<div class="relative flex items-center lg:space-x-2">
|
{% if user.is_authenticated %}
|
||||||
|
{% include 'components/generic/user_dropdown.html' %}
|
||||||
{% include 'components/theme-switch.html' %}
|
|
||||||
<!-- Show/Hide cart -->
|
|
||||||
<div id="navbar-cart-dropdown" hx-get="{% url 'web:cart_dropdown' %}"
|
|
||||||
hx-trigger="load, updated-cart from:body"></div>
|
|
||||||
|
|
||||||
{% if request.user.is_authenticated %}
|
|
||||||
<!-- Show/Hide user account dropdown -->
|
|
||||||
<button
|
|
||||||
hx-on:click="htmx.toggleClass(htmx.find('#userDropdown1'), 'hidden'); htmx.addClass(htmx.find('#myCartDropdown1'), 'hidden')"
|
|
||||||
id="userDropdownButton1"
|
|
||||||
data-dropdown-toggle="userDropdown1" type="button"
|
|
||||||
aria-label="show menu"
|
|
||||||
class="icon-button">
|
|
||||||
{% include 'components/icons/user.svg' %}
|
|
||||||
<span class="hidden sm:flex">
|
|
||||||
{% translate 'Mi cuenta' %}
|
|
||||||
</span>
|
|
||||||
{% include 'components/icons/dropdown.svg' %}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- User account dropdown -->
|
|
||||||
<div id="userDropdown1"
|
|
||||||
class="absolute top-12 hidden z-12 w-56 divide-y divide-gray-100 overflow-hidden overflow-y-auto rounded-lg bg-white antialiased shadow dark:divide-gray-600 dark:bg-gray-700 right-0">
|
|
||||||
{% include 'components/users/user_dropdown.html' %}
|
|
||||||
</div>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'web:login' %}"
|
<a href="{% url 'users:login' %}"
|
||||||
class="link-button">
|
class="link-button flex items-center">
|
||||||
{% translate 'Inicia sesión' %}
|
{% translate 'Inicia sesión' %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Show/Hide menu items -->
|
|
||||||
<button hx-on:click="htmx.toggleClass(htmx.find('#ecommerce-navbar-menu-1'), 'hidden')" type="button"
|
|
||||||
data-collapse-toggle="ecommerce-navbar-menu-1" aria-controls="ecommerce-navbar-menu-1"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="show menu"
|
|
||||||
class="icon-button lg:hidden">
|
|
||||||
<span class="sr-only">
|
|
||||||
{% translate 'Abrir menú' %}
|
|
||||||
</span>
|
|
||||||
{% include 'components/icons/burger.svg' %}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="ecommerce-navbar-menu-1"
|
|
||||||
class="navbar-dropdown-menu hidden">
|
|
||||||
<ul class="navbar-dropdown-menu-list">
|
|
||||||
<li>
|
|
||||||
<a href="{% url 'web:index' %}"
|
|
||||||
class="navbar-dropdown-menu-title">{% translate 'Inicio' %}</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
{% for category in navbar_categories %}
|
|
||||||
<li>
|
|
||||||
<a href="{% url 'web:category_view' slug=category.slug %}"
|
|
||||||
class="navbar-dropdown-menu-title">{{ category.name }}</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div role="status">
|
<div role="status">
|
||||||
<svg aria-hidden="true" class="w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-primary-600"
|
<svg aria-hidden="true" class="w-8 h-8 animate-spin fill-primary-600"
|
||||||
viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
|
viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<path
|
||||||
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
id="theme-toggle"
|
id="theme-toggle"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="switchtheme"
|
aria-label="switchtheme"
|
||||||
class="icon-button">
|
class="btn btn-circle">
|
||||||
{% include 'components/icons/moon.svg' %}
|
{% include 'components/icons/moon.svg' %}
|
||||||
{% include 'components/icons/sun.svg' %}
|
{% include 'components/icons/sun.svg' %}
|
||||||
</button>
|
</button>
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<div id="toast-default"
|
<div id="toast-default"
|
||||||
class="flex items-center w-full max-w-xs p-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800"
|
class="flex items-center w-full max-w-xs p-4 rounded-lg shadow "
|
||||||
role="alert"
|
role="alert"
|
||||||
>
|
>
|
||||||
<div class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-blue-500 bg-blue-100 rounded-lg dark:bg-blue-800 dark:text-blue-200">
|
<div class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-blue-500 rounded-lg ">
|
||||||
{% block icon %}
|
{% block icon %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -11,9 +11,9 @@
|
|||||||
{% block toast_text %}{% endblock %}
|
{% block toast_text %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="ms-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2
|
class="ms-auto -mx-1.5 -my-1.5 hover: rounded-lg focus:ring-2
|
||||||
focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex items-center justify-center h-8 w-8
|
focus:ring-gray-300 p-1.5 hover: inline-flex items-center justify-center h-8 w-8
|
||||||
dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700 cursor-pointer"
|
:text-white : cursor-pointer"
|
||||||
data-dismiss-target="#toast-default" aria-label="Close"
|
data-dismiss-target="#toast-default" aria-label="Close"
|
||||||
hx-on:click="htmx.toggleClass(htmx.find('#toast-default'), 'hidden')"
|
hx-on:click="htmx.toggleClass(htmx.find('#toast-default'), 'hidden')"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
<div class="dropdown dropdown-end">
|
||||||
|
<div tabindex="0" role="button" class="btn btn-circle avatar">
|
||||||
|
<div class="w-10 flex rounded-full justify-center items-center">
|
||||||
|
{{ request.user.first_name.0 | upper }}{{ request.user.last_name.0 | upper }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
tabindex="-1"
|
||||||
|
class="menu menu-sm dropdown-content bg-base-100 rounded-box z-1 mt-3 w-52 p-2 shadow">
|
||||||
|
<li>
|
||||||
|
<a class="justify-between" href="{% url 'users:my_account' %}">
|
||||||
|
{% trans 'Mi cuenta' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li><a>{% trans 'Ajustes' %}</a></li>
|
||||||
|
<li><a href="{% url 'users:logout' %}">{% trans 'Cerrar sesión' %}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<article>
|
<article>
|
||||||
<div
|
<div
|
||||||
class="card">
|
>
|
||||||
<div class="h-56 w-full bg-gray-200 dark:bg-gray-950">
|
<div class="h-56 w-full ">
|
||||||
<a href="{% url 'web:product_detail' pk=product.pk slug=product.slug %}">
|
<a href="{% url 'web:product_detail' pk=product.pk slug=product.slug %}">
|
||||||
<img class="mx-auto h-full dark:hidden" src="{{ product.images.all.0.m.url }}"
|
<img class="mx-auto h-full " src="{{ product.images.all.0.m.url }}"
|
||||||
alt="{{ product.name }}"/>
|
alt="{{ product.name }}"/>
|
||||||
<img class="mx-auto hidden h-full dark:block" src="{{ product.images.all.0.m_dark.url }}"
|
<img class="mx-auto hidden h-full " src="{{ product.images.all.0.m_dark.url }}"
|
||||||
alt="{{ product.name }}"/>
|
alt="{{ product.name }}"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
<!-- {% include 'components/icons/star.svg' %}-->
|
<!-- {% include 'components/icons/star.svg' %}-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
|
|
||||||
<!-- <p class="text-sm font-medium text-gray-900 dark:text-white">5.0</p>-->
|
<!-- <p class="text-sm font-medium ">5.0</p>-->
|
||||||
<!-- <p class="text-sm font-medium text-gray-500 dark:text-gray-400">(455)</p>-->
|
<!-- <p class="text-sm font-medium ">(455)</p>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<div class="mt-4 flex gap-4">
|
<div class="mt-4 flex gap-4">
|
||||||
<p class="txt-2xl">
|
<p class="txt-2xl">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<section class="bg-gray-50 dark:bg-gray-900 flex items-center my-4">
|
<section class=" flex items-center my-4">
|
||||||
<div class="max-w-screen-xl px-4 mx-auto lg:px-12 w-full">
|
<div class="max-w-screen-xl px-4 mx-auto lg:px-12 w-full">
|
||||||
<div class="relative bg-white shadow-md dark:bg-gray-800 sm:rounded-lg">
|
<div class="relative shadow-md sm:rounded-lg">
|
||||||
<div class="flex flex-col items-center justify-between p-4 space-y-3 md:flex-row md:space-y-0 md:space-x-4">
|
<div class="flex flex-col items-center justify-between p-4 space-y-3 md:flex-row md:space-y-0 md:space-x-4">
|
||||||
<div class="w-full md:w-full">
|
<div class="w-full md:w-full">
|
||||||
<form class="flex items-center"
|
<form class="flex items-center"
|
||||||
@@ -11,19 +11,27 @@
|
|||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-push="true"
|
hx-push="true"
|
||||||
>
|
>
|
||||||
<label for="simple-search" class="sr-only">{% translate 'Buscar' %}</label>
|
<label for="simple-search" class="input w-full">
|
||||||
<div class="relative w-full">
|
<svg class="h-[1em] opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
|
<g
|
||||||
{% include 'components/icons/search.svg' %}
|
stroke-linejoin="round"
|
||||||
</div>
|
stroke-linecap="round"
|
||||||
|
stroke-width="2.5"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<circle cx="11" cy="11" r="8"></circle>
|
||||||
|
<path d="m21 21-4.3-4.3"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="search"
|
||||||
name="name"
|
name="name"
|
||||||
id="simple-search"
|
id="simple-search"
|
||||||
class="search-input"
|
|
||||||
placeholder="{% translate 'Buscar' %}"
|
placeholder="{% translate 'Buscar' %}"
|
||||||
autocomplete="off">
|
autocomplete="off">
|
||||||
</div>
|
</label>
|
||||||
|
|
||||||
{% if filter_by_category %}
|
{% if filter_by_category %}
|
||||||
<input type="hidden" name="category" value="{{ category.id }}">
|
<input type="hidden" name="category" value="{{ category.id }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label for="{{ field.id_for_label }}"
|
<label for="{{ field.id_for_label }}"
|
||||||
class="inline-block text-sm font-medium text-gray-900 dark:text-white ml-2">
|
class="inline-block text-sm font-medium ml-2">
|
||||||
{{ field.label }}
|
{{ field.label }}
|
||||||
</label>
|
</label>
|
||||||
{{ field }}
|
{{ field }}
|
||||||
@@ -13,12 +13,12 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% for k, error in form.errors.items %}
|
{% for k, error in form.errors.items %}
|
||||||
<span class="flex justify-center mb-2 text-sm font-medium text-red-900 dark:text-red-400">{{ error }}</span>
|
<span class="flex justify-center mb-2 text-sm font-medium text-red-900 ">{{ error }}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<button class="text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none
|
<button class="text-white hover: focus:ring-4 focus:outline-none
|
||||||
focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600
|
focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center
|
||||||
dark:hover:bg-primary-700 dark:focus:ring-primary-800 cursor-pointer"
|
: :ring-primary-800 cursor-pointer"
|
||||||
>
|
>
|
||||||
{% translate 'Guardar' %}
|
{% translate 'Guardar' %}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -12,71 +12,65 @@
|
|||||||
<div class="mb-4 grid gap-4 sm:grid-cols-2 sm:gap-8 lg:gap-16">
|
<div class="mb-4 grid gap-4 sm:grid-cols-2 sm:gap-8 lg:gap-16">
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">
|
<dt class="font-semibold ">
|
||||||
<label for="address_full_name">
|
<label for="address_full_name">
|
||||||
{% translate 'Nombre completo' %}
|
{% translate 'Nombre completo' %}
|
||||||
</label>
|
</label>
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="flex items-center gap-1 text-gray-500 dark:text-gray-400">
|
<dd class="flex items-center gap-1 ">
|
||||||
<input class="input-text"
|
<input class="input" id="address_full_name" name="full_name" type="text" value="{{ address.full_name }}">
|
||||||
id="address_full_name" name="full_name" type="text" value="{{ address.full_name }}">
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">
|
<dt class="font-semibold ">
|
||||||
<label for="address">
|
<label for="address">
|
||||||
{% translate 'Dirección' %}
|
{% translate 'Dirección' %}
|
||||||
</label>
|
</label>
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="flex items-center gap-1 text-gray-500 dark:text-gray-400">
|
<dd class="flex items-center gap-1 ">
|
||||||
<input class="input-text"
|
<input class="input" id="address" name="address" type="text" value="{{ address.address }}">
|
||||||
id="address" name="address" type="text" value="{{ address.address }}">
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">
|
<dt class="font-semibold ">
|
||||||
<label for="address_zip">
|
<label for="address_zip">
|
||||||
{% translate 'Código postal' %}
|
{% translate 'Código postal' %}
|
||||||
</label>
|
</label>
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-gray-500 dark:text-gray-400">
|
<dd class=" ">
|
||||||
<input class="input-text"
|
<input class="input" id="address_zip" name="address_zip" type="text" value="{{ address.address_zip }}">
|
||||||
id="address_zip" name="address_zip" type="text" value="{{ address.address_zip }}">
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">
|
<dt class="font-semibold ">
|
||||||
<label for="address_phone">
|
<label for="address_phone">
|
||||||
{% translate 'Teléfono' %}
|
{% translate 'Teléfono' %}
|
||||||
</label>
|
</label>
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-gray-500 dark:text-gray-400">
|
<dd class=" ">
|
||||||
<input class="input-text"
|
<input class="input" id="address_phone" name="address_phone" type="text" value="{{ address.address_phone }}">
|
||||||
id="address_phone" name="address_phone" type="text" value="{{ address.address_phone }}">
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">
|
<dt class="font-semibold ">
|
||||||
<label for="address_town">
|
<label for="address_town">
|
||||||
{% translate 'Localidad' %}
|
{% translate 'Localidad' %}
|
||||||
</label>
|
</label>
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-gray-500 dark:text-gray-400">
|
<dd class=" ">
|
||||||
<input class="input-text"
|
<input class="input" id="address_town" name="address_town" type="text" value="{{ address.address_town }}">
|
||||||
id="address_town" name="address_town" type="text" value="{{ address.address_town }}">
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">
|
<dt class="font-semibold ">
|
||||||
<label for="address_state">
|
<label for="address_state">
|
||||||
{% translate 'Provincia' %}
|
{% translate 'Provincia' %}
|
||||||
</label>
|
</label>
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-gray-500 dark:text-gray-400">
|
<dd class=" ">
|
||||||
<input class="input-text"
|
<input class="input" id="address_state" name="address_state" type="text" value="{{ address.address_state }}">
|
||||||
id="address_state" name="address_state" type="text" value="{{ address.address_state }}">
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,9 +78,9 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<button class="text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none
|
<button class="text-white hover: focus:ring-4 focus:outline-none
|
||||||
focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600
|
focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center
|
||||||
dark:hover:bg-primary-700 dark:focus:ring-primary-800 cursor-pointer"
|
: :ring-primary-800 cursor-pointer"
|
||||||
>
|
>
|
||||||
{% translate 'Guardar' %}
|
{% translate 'Guardar' %}
|
||||||
</button>
|
</button>
|
||||||
@@ -98,34 +92,34 @@
|
|||||||
<div class="mb-4 grid gap-4 sm:grid-cols-2 sm:gap-8 lg:gap-16">
|
<div class="mb-4 grid gap-4 sm:grid-cols-2 sm:gap-8 lg:gap-16">
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">{% translate 'Nombre completo' %}</dt>
|
<dt class="font-semibold ">{% translate 'Nombre completo' %}</dt>
|
||||||
<dd class="flex items-center gap-1 text-gray-500 dark:text-gray-400">
|
<dd class="flex items-center gap-1 ">
|
||||||
{{ address.full_name }}
|
{{ address.full_name }}
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">{% translate 'Dirección' %}</dt>
|
<dt class="font-semibold ">{% translate 'Dirección' %}</dt>
|
||||||
<dd class="flex items-center gap-1 text-gray-500 dark:text-gray-400">
|
<dd class="flex items-center gap-1 ">
|
||||||
{{ address.address }}
|
{{ address.address }}
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">{% translate 'Código postal' %}</dt>
|
<dt class="font-semibold ">{% translate 'Código postal' %}</dt>
|
||||||
<dd class="text-gray-500 dark:text-gray-400">{{ address.address_zip }}</dd>
|
<dd class=" ">{{ address.address_zip }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">{% translate 'Teléfono' %}</dt>
|
<dt class="font-semibold ">{% translate 'Teléfono' %}</dt>
|
||||||
<dd class="text-gray-500 dark:text-gray-400">{{ address.address_phone }}</dd>
|
<dd class=" ">{{ address.address_phone }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">{% translate 'Localidad' %}</dt>
|
<dt class="font-semibold ">{% translate 'Localidad' %}</dt>
|
||||||
<dd class="text-gray-500 dark:text-gray-400">{{ address.address_town }}</dd>
|
<dd class=" ">{{ address.address_town }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="font-semibold text-gray-900 dark:text-white">{% translate 'Provincia' %}</dt>
|
<dt class="font-semibold ">{% translate 'Provincia' %}</dt>
|
||||||
<dd class="text-gray-500 dark:text-gray-400">{{ address.address_state }}</dd>
|
<dd class=" ">{{ address.address_state }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -133,9 +127,9 @@
|
|||||||
<button hx-on:click="htmx.toggleClass(htmx.find('#edit_address_{{ address.pk }}'), 'hidden'); htmx.toggleClass(htmx.find('#details_address_{{ address.pk }}'), 'hidden')"
|
<button hx-on:click="htmx.toggleClass(htmx.find('#edit_address_{{ address.pk }}'), 'hidden'); htmx.toggleClass(htmx.find('#details_address_{{ address.pk }}'), 'hidden')"
|
||||||
type="button"
|
type="button"
|
||||||
data-modal-target="accountInformationModal2" data-modal-toggle="accountInformationModal2"
|
data-modal-target="accountInformationModal2" data-modal-toggle="accountInformationModal2"
|
||||||
class="inline-flex w-full items-center justify-center rounded-lg bg-primary-700 px-5 py-2.5 text-sm
|
class="inline-flex w-full items-center justify-center rounded-lg px-5 py-2.5 text-sm
|
||||||
font-medium text-white hover:bg-primary-800 focus:outline-none focus:ring-4 focus:ring-primary-300
|
font-medium text-white hover: focus:outline-none focus:ring-4 focus:ring-primary-300
|
||||||
dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 sm:w-auto cursor-pointer"
|
: :ring-primary-800 sm:w-auto cursor-pointer"
|
||||||
>
|
>
|
||||||
{% include 'components/icons/edit.svg' %}
|
{% include 'components/icons/edit.svg' %}
|
||||||
{% translate 'Editar datos' %}
|
{% translate 'Editar datos' %}
|
||||||
@@ -143,6 +137,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if not forloop.last %}
|
{% if not forloop.last %}
|
||||||
<hr class="h-px my-2 bg-gray-200 border-0 dark:bg-gray-700">
|
<hr class="h-px my-2 ">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<ul class="p-2 text-start text-sm font-medium text-gray-900 dark:text-white">
|
<ul class="p-2 text-start text-sm font-medium ">
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'web:my_account' %}" title=""
|
<a href="{% url 'users:my_account' %}" title=""
|
||||||
class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600">
|
class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover: :">
|
||||||
{% translate 'Mi cuenta' %}
|
{% translate 'Mi cuenta' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'web:orders' %}" title=""
|
<a href="{% url 'web:orders' %}" title=""
|
||||||
class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600">
|
class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover: :">
|
||||||
{% translate 'Mis pedidos' %}
|
{% translate 'Mis pedidos' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'web:wishlist' %}" title=""
|
<a href="{% url 'web:wishlist' %}" title=""
|
||||||
class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600">
|
class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover: :">
|
||||||
{% translate 'Lista de deseados' %}
|
{% translate 'Lista de deseados' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="p-2 text-sm font-medium text-gray-900 dark:text-white">
|
<div class="p-2 text-sm font-medium ">
|
||||||
<a href="{% url 'web:logout' %}" title=""
|
<a href="{% url 'users:logout' %}" title=""
|
||||||
class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600">
|
class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover: :">
|
||||||
{% translate 'Cerrar sesión' %}
|
{% translate 'Cerrar sesión' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,27 +12,15 @@
|
|||||||
<link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}"/>
|
<link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}"/>
|
||||||
<script src="https://unpkg.com/htmx.org@2.0.3"></script>
|
<script src="https://unpkg.com/htmx.org@2.0.3"></script>
|
||||||
|
|
||||||
<!-- Shoelace -->
|
<link href="https://cdn.jsdelivr.net/npm/daisyui@5" rel="stylesheet" type="text/css" />
|
||||||
<link
|
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||||
rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/daisyui@5/themes.css" rel="stylesheet" type="text/css" />
|
||||||
media="(prefers-color-scheme:light)"
|
|
||||||
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.19.1/cdn/themes/light.css"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
media="(prefers-color-scheme:dark)"
|
|
||||||
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.19.1/cdn/themes/dark.css"
|
|
||||||
onload="document.documentElement.classList.add('sl-theme-dark');"
|
|
||||||
/>
|
|
||||||
<script type="module"
|
|
||||||
src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.19.1/cdn/shoelace-autoloader.js"></script>
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
|
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-50 dark:bg-gray-900">
|
<body>
|
||||||
<main>
|
<main>
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
{% extends 'theme/base.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
<section class="bg-gray-50 dark:bg-gray-900">
|
|
||||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
|
||||||
|
|
||||||
<a href="{% url 'web:index' %}" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
|
||||||
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
|
||||||
{{ web_title }}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
|
||||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
|
||||||
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
|
||||||
{% translate 'Restablecer contraseña' %}
|
|
||||||
</h1>
|
|
||||||
<form action="{% url 'web:reset_password' %}" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% for field in form %}
|
|
||||||
|
|
||||||
<div class="my-2">
|
|
||||||
<label for="{{ field.id_for_label }}"
|
|
||||||
class="inline-block text-sm font-medium text-gray-900 dark:text-white mr-2">
|
|
||||||
{{ field.label }}
|
|
||||||
</label>
|
|
||||||
{{ field }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
<button
|
|
||||||
class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 cursor-pointer">
|
|
||||||
{% translate 'Restablecer contraseña' %}
|
|
||||||
</button>
|
|
||||||
<p class="text-sm font-light text-gray-500 mt-4 dark:text-gray-400">
|
|
||||||
{% translate '¿Aún no tienes cuenta?' %}
|
|
||||||
<a href="{% url 'web:register' %}" class="font-medium text-primary-600 hover:underline dark:text-primary-500">{% translate 'Regístrate aquí' %}</a>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<div class="flex justify-center items-center">
|
<div class="flex justify-center items-center">
|
||||||
{% if has_previous_page %}
|
{% if has_previous_page %}
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="button-gray"
|
|
||||||
hx-get="{% url 'web:list_products' %}{% querystring page=page.previous_page_number %}"
|
hx-get="{% url 'web:list_products' %}{% querystring page=page.previous_page_number %}"
|
||||||
hx-trigger="click"
|
hx-trigger="click"
|
||||||
hx-target="#products"
|
hx-target="#products"
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if has_next_page %}
|
{% if has_next_page %}
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="button-gray"
|
|
||||||
hx-get="{% url 'web:list_products' %}{% querystring page=page.next_page_number %}"
|
hx-get="{% url 'web:list_products' %}{% querystring page=page.next_page_number %}"
|
||||||
hx-trigger="click"
|
hx-trigger="click"
|
||||||
hx-target="#products"
|
hx-target="#products"
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
{% block main %}
|
{% block main %}
|
||||||
{% include 'components/generic/navbar.html' %}
|
{% include 'components/generic/navbar.html' %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<section class="bg-white py-2 antialiased dark:bg-gray-900 md:py-8">
|
<section class=" py-2 antialiased md:py-8">
|
||||||
<div class="mx-auto max-w-screen-xl px-4 2xl:px-0">
|
<div class="mx-auto max-w-screen-xl px-4 2xl:px-0">
|
||||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">
|
<h2 class="text-xl font-semibold sm:text-2xl">
|
||||||
{% translate 'Resumen del pedido' %}
|
{% translate 'Resumen del pedido' %}
|
||||||
|
|
||||||
{% if order.status == 'PAI' %}
|
{% if order.status == 'PAI' %}
|
||||||
<span class="bg-green-100 text-green-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded dark:bg-green-900 dark:text-green-300 ml-3">{% trans 'Pagado' %}</span>
|
<span class=" text-green-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded ml-3">{% trans 'Pagado' %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
@@ -20,25 +20,25 @@
|
|||||||
|
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
<div
|
<div
|
||||||
class="rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-800 md:p-6">
|
class="rounded-lg p-4 shadow-sm md:p-6">
|
||||||
<div class="space-y-4 md:flex md:items-center md:justify-between md:gap-6 md:space-y-0">
|
<div class="space-y-4 md:flex md:items-center md:justify-between md:gap-6 md:space-y-0">
|
||||||
<a href="#" class="shrink-0 md:order-1">
|
<a href="#" class="shrink-0 md:order-1">
|
||||||
<img class="h-20 w-20 dark:hidden" src="{{ item.product.images.all.0.s.url }}"
|
<img class="h-20 w-20 " src="{{ item.product.images.all.0.s.url }}"
|
||||||
alt="{{ item.product.name }}"/>
|
alt="{{ item.product.name }}"/>
|
||||||
<img class="hidden h-20 w-20 dark:block" src="{{ item.product.images.all.0.s_dark.url }}"
|
<img class="hidden h-20 w-20 " src="{{ item.product.images.all.0.s_dark.url }}"
|
||||||
alt="{{ item.product.name }}"/>
|
alt="{{ item.product.name }}"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="flex items-center justify-between md:order-3 md:justify-end">
|
<div class="flex items-center justify-between md:order-3 md:justify-end">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span
|
<span
|
||||||
class="w-10 shrink-0 border-0 bg-transparent text-center text-sm font-medium text-gray-900 focus:outline-none focus:ring-0 dark:text-white">
|
class="w-10 shrink-0 text-center text-sm font-medium focus:outline-none focus:ring-0 ">
|
||||||
{{ item.quantity|floatformat }}x
|
{{ item.quantity|floatformat }}x
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-end md:order-4 md:w-32">
|
<div class="text-end md:order-4 md:w-32">
|
||||||
<p
|
<p
|
||||||
class="text-base font-bold text-gray-900 dark:text-white">
|
class="text-base font-bold ">
|
||||||
{{ item.product.price.price_with_tax }}€
|
{{ item.product.price.price_with_tax }}€
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
<div class="w-full min-w-0 flex-1 space-y-4 md:order-2 md:max-w-md">
|
<div class="w-full min-w-0 flex-1 space-y-4 md:order-2 md:max-w-md">
|
||||||
<a href="{% url 'web:product_detail' pk=item.product.pk slug=item.product.slug %}"
|
<a href="{% url 'web:product_detail' pk=item.product.pk slug=item.product.slug %}"
|
||||||
class="text-base font-medium text-gray-900 hover:underline dark:text-white"
|
class="text-base font-medium hover:underline "
|
||||||
>
|
>
|
||||||
{{ item.product.name }}
|
{{ item.product.name }}
|
||||||
</a>
|
</a>
|
||||||
@@ -58,53 +58,53 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if items.count == 0 %}
|
{% if items.count == 0 %}
|
||||||
<p class="text-base font-normal text-gray-500 dark:text-gray-400">
|
<p class="text-base font-normal ">
|
||||||
{% translate 'No hay nada en el carrito...' %}
|
{% translate 'No hay nada en el carrito...' %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="{% url 'web:index' %}" title=""
|
<a href="{% url 'web:index' %}" title=""
|
||||||
class="inline-flex items-center gap-2 text-sm font-medium text-primary-700 underline hover:no-underline dark:text-primary-500">
|
class="inline-flex items-center gap-2 text-sm font-medium text-primary-700 underline hover:no-underline ">
|
||||||
{% translate 'Volver a inicio' %}
|
{% translate 'Volver a inicio' %}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">
|
<h2 class="text-xl font-semibold sm:text-2xl">
|
||||||
{% translate 'Dirección de envío' %}
|
{% translate 'Dirección de envío' %}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.email }}</p>
|
<p class="text-m ">{{ order.email }}</p>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.shipping_address }}</p>
|
<p class="text-m ">{{ order.shipping_address }}</p>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.shipping_city }}</p>
|
<p class="text-m ">{{ order.shipping_city }}</p>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.shipping_state }}</p>
|
<p class="text-m ">{{ order.shipping_state }}</p>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.shipping_country }}</p>
|
<p class="text-m ">{{ order.shipping_country }}</p>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.shipping_zip }}</p>
|
<p class="text-m ">{{ order.shipping_zip }}</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">
|
<h2 class="text-xl font-semibold sm:text-2xl">
|
||||||
{% translate 'Dirección de facturación' %}
|
{% translate 'Dirección de facturación' %}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.billing_address }}</p>
|
<p class="text-m ">{{ order.billing_address }}</p>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.billing_city }}</p>
|
<p class="text-m ">{{ order.billing_city }}</p>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.billing_state }}</p>
|
<p class="text-m ">{{ order.billing_state }}</p>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.billing_country }}</p>
|
<p class="text-m ">{{ order.billing_country }}</p>
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.billing_zip }}</p>
|
<p class="text-m ">{{ order.billing_zip }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">
|
<h2 class="text-xl font-semibold sm:text-2xl">
|
||||||
{% translate 'Método de envío' %}
|
{% translate 'Método de envío' %}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p class="text-m text-gray-900 dark:text-white">{{ order.shipping_method.name }}</p>
|
<p class="text-m ">{{ order.shipping_method.name }}</p>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@@ -114,23 +114,23 @@
|
|||||||
<!-- Resumen del pedido -->
|
<!-- Resumen del pedido -->
|
||||||
<div class="mx-auto mt-6 max-w-4xl flex-1 space-y-6 lg:mt-0 lg:w-full">
|
<div class="mx-auto mt-6 max-w-4xl flex-1 space-y-6 lg:mt-0 lg:w-full">
|
||||||
<div
|
<div
|
||||||
class="space-y-4 rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-800 sm:p-6">
|
class="space-y-4 rounded-lg p-4 shadow-sm sm:p-6">
|
||||||
<p class="text-xl font-semibold text-gray-900 dark:text-white">
|
<p class="text-xl font-semibold ">
|
||||||
{% translate 'Resumen del pedido' %}</p>
|
{% translate 'Resumen del pedido' %}</p>
|
||||||
|
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<dl class="flex items-center justify-between gap-4">
|
<dl class="flex items-center justify-between gap-4">
|
||||||
<dt
|
<dt
|
||||||
class="text-base font-normal text-gray-500 dark:text-gray-400">
|
class="text-base font-normal ">
|
||||||
{% translate 'Base imponible' %}
|
{% translate 'Base imponible' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-base font-medium text-gray-900 dark:text-white">{{ base_total }} €
|
<dd class="text-base font-medium ">{{ base_total }} €
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<dl class="flex items-center justify-between gap-4">
|
<dl class="flex items-center justify-between gap-4">
|
||||||
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">
|
<dt class="text-base font-normal ">
|
||||||
{% translate 'Descuentos' %}
|
{% translate 'Descuentos' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-base font-medium text-green-600">-{{ savings }} €</dd>
|
<dd class="text-base font-medium text-green-600">-{{ savings }} €</dd>
|
||||||
@@ -138,27 +138,27 @@
|
|||||||
|
|
||||||
<dl class="flex items-center justify-between gap-4">
|
<dl class="flex items-center justify-between gap-4">
|
||||||
<dt
|
<dt
|
||||||
class="text-base font-normal text-gray-500 dark:text-gray-400">
|
class="text-base font-normal ">
|
||||||
{% translate 'Gastos de envío' %}
|
{% translate 'Gastos de envío' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-base font-medium text-gray-900 dark:text-white">{{ shipping_cost }}
|
<dd class="text-base font-medium ">{{ shipping_cost }}
|
||||||
€
|
€
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<dl class="flex items-center justify-between gap-4">
|
<dl class="flex items-center justify-between gap-4">
|
||||||
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">
|
<dt class="text-base font-normal ">
|
||||||
{% translate 'Impuestos' %}
|
{% translate 'Impuestos' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-base font-medium text-gray-900 dark:text-white">{{ tax_total }} €
|
<dd class="text-base font-medium ">{{ tax_total }} €
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<dl class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dark:border-gray-700">
|
<dl class="flex items-center justify-between gap-4 pt-2 ">
|
||||||
<dt class="text-base font-bold text-gray-900 dark:text-white">{% translate 'Total' %}
|
<dt class="text-base font-bold ">{% translate 'Total' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="text-base font-bold text-gray-900 dark:text-white">{{ total }} €</dd>
|
<dd class="text-base font-bold ">{{ total }} €</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -169,14 +169,14 @@
|
|||||||
<input type="hidden" name="Ds_MerchantParameters" value="{{ merchant_parameters }}"/>
|
<input type="hidden" name="Ds_MerchantParameters" value="{{ merchant_parameters }}"/>
|
||||||
<input type="hidden" name="Ds_Signature" value="{{ signature }}"/>
|
<input type="hidden" name="Ds_Signature" value="{{ signature }}"/>
|
||||||
|
|
||||||
<button class="flex w-full items-center justify-center rounded-lg bg-primary-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-primary-800 focus:outline-none focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 cursor-pointer">
|
<button class="flex w-full items-center justify-center rounded-lg px-5 py-2.5 text-sm font-medium text-white hover: focus:outline-none focus:ring-4 focus:ring-primary-300 : :ring-primary-800 cursor-pointer">
|
||||||
{% translate 'Pagar' %}
|
{% translate 'Pagar' %}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<div class="flex items-center justify-center gap-2">
|
<div class="flex items-center justify-center gap-2">
|
||||||
<span class="text-sm font-normal text-gray-500 dark:text-gray-400"> {% translate 'o' %} </span>
|
<span class="text-sm font-normal "> {% translate 'o' %} </span>
|
||||||
<a href="{% url 'web:index' %}" title=""
|
<a href="{% url 'web:index' %}" title=""
|
||||||
class="inline-flex items-center gap-2 text-sm font-medium text-primary-700 underline hover:no-underline dark:text-primary-400">
|
class="inline-flex items-center gap-2 text-sm font-medium text-primary-700 underline hover:no-underline ">
|
||||||
{% translate 'Seguir comprando' %}
|
{% translate 'Seguir comprando' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,20 +6,20 @@
|
|||||||
<div class="mx-auto max-w-screen-xl px-4 2xl:px-0">
|
<div class="mx-auto max-w-screen-xl px-4 2xl:px-0">
|
||||||
<div class="mx-auto max-w-5xl">
|
<div class="mx-auto max-w-5xl">
|
||||||
<div class="gap-4">
|
<div class="gap-4">
|
||||||
<h1 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl my-4">
|
<h1 class="text-xl font-semibold sm:text-2xl my-4">
|
||||||
{% translate 'Mis pedidos' %}
|
{% translate 'Mis pedidos' %}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="mt-6 flow-root sm:mt-8">
|
<div class="mt-6 flow-root sm:mt-8">
|
||||||
<div class="divide-y divide-gray-200 dark:divide-gray-700">
|
<div class="divide-y divide-gray-200 ">
|
||||||
{% for order in page %}
|
{% for order in page %}
|
||||||
|
|
||||||
<article class="flex flex-wrap items-center gap-y-4 py-6">
|
<article class="flex flex-wrap items-center gap-y-4 py-6">
|
||||||
<dl class="w-1/2 sm:w-1/4 lg:w-auto lg:flex-1 px-4">
|
<dl class="w-1/2 sm:w-1/4 lg:w-auto lg:flex-1 px-4">
|
||||||
<dt class="text-base font-medium text-gray-500 dark:text-gray-400">
|
<dt class="text-base font-medium ">
|
||||||
{% translate 'Número de pedido' %}
|
{% translate 'Número de pedido' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-1.5 text-base font-semibold text-gray-900 dark:text-white">
|
<dd class="mt-1.5 text-base font-semibold ">
|
||||||
<a href="{% url 'web:order' uuid=order.uuid %}" class="hover:underline">
|
<a href="{% url 'web:order' uuid=order.uuid %}" class="hover:underline">
|
||||||
#{{ order.code }}
|
#{{ order.code }}
|
||||||
</a>
|
</a>
|
||||||
@@ -27,19 +27,19 @@
|
|||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<dl class="w-1/2 sm:w-1/4 lg:w-auto lg:flex-1 px-4">
|
<dl class="w-1/2 sm:w-1/4 lg:w-auto lg:flex-1 px-4">
|
||||||
<dt class="text-base font-medium text-gray-500 dark:text-gray-400">
|
<dt class="text-base font-medium ">
|
||||||
{% translate 'Fecha' %}
|
{% translate 'Fecha' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-1.5 text-base font-semibold text-gray-900 dark:text-white">
|
<dd class="mt-1.5 text-base font-semibold ">
|
||||||
{{ order.creation_date }}
|
{{ order.creation_date }}
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<dl class="w-1/2 sm:w-1/4 lg:w-auto lg:flex-1 px-4">
|
<dl class="w-1/2 sm:w-1/4 lg:w-auto lg:flex-1 px-4">
|
||||||
<dt class="text-base font-medium text-gray-500 dark:text-gray-400">
|
<dt class="text-base font-medium ">
|
||||||
{% translate 'Total' %}
|
{% translate 'Total' %}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-1.5 text-base font-semibold text-gray-900 dark:text-white">
|
<dd class="mt-1.5 text-base font-semibold ">
|
||||||
{{ order.total }}€
|
{{ order.total }}€
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
@@ -47,45 +47,45 @@
|
|||||||
<dl class="w-1/2 sm:w-1/4 lg:w-auto lg:flex-1 px-4">
|
<dl class="w-1/2 sm:w-1/4 lg:w-auto lg:flex-1 px-4">
|
||||||
|
|
||||||
{% if order.status == 'PAI' %}
|
{% if order.status == 'PAI' %}
|
||||||
<dd class="inline-flex bg-green-100 text-green-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-green-900 dark:text-green-300">
|
<dd class="inline-flex text-green-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded ">
|
||||||
{% translate 'Pagado' %}
|
{% translate 'Pagado' %}
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
{% if order.shipping_status == 'NOT' %}
|
{% if order.shipping_status == 'NOT' %}
|
||||||
<dd class="inline-flex bg-yellow-100 text-yellow-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-yellow-900 dark:text-yellow-300">
|
<dd class="inline-flex text-yellow-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded ">
|
||||||
{% translate 'Tramitado' %}
|
{% translate 'Tramitado' %}
|
||||||
</dd>
|
</dd>
|
||||||
{% elif order.shipping_status == 'RDY' %}
|
{% elif order.shipping_status == 'RDY' %}
|
||||||
<dd class="inline-flex bg-yellow-100 text-yellow-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-yellow-900 dark:text-yellow-300">
|
<dd class="inline-flex text-yellow-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded ">
|
||||||
{% translate 'Preparado' %}
|
{% translate 'Preparado' %}
|
||||||
</dd>
|
</dd>
|
||||||
{% elif order.shipping_status == 'TBS' %}
|
{% elif order.shipping_status == 'TBS' %}
|
||||||
<dd class="inline-flex bg-yellow-100 text-yellow-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-yellow-900 dark:text-yellow-300">
|
<dd class="inline-flex text-yellow-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded ">
|
||||||
{% translate 'Listo' %}
|
{% translate 'Listo' %}
|
||||||
</dd>
|
</dd>
|
||||||
{% elif order.shipping_status == 'SNT' %}
|
{% elif order.shipping_status == 'SNT' %}
|
||||||
<dd class="inline-flex bg-blue-100 text-blue-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300">
|
<dd class="inline-flex text-blue-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded ">
|
||||||
{% translate 'Enviado' %}
|
{% translate 'Enviado' %}
|
||||||
</dd>
|
</dd>
|
||||||
{% elif order.shipping_status == 'DLV' %}
|
{% elif order.shipping_status == 'DLV' %}
|
||||||
<dd class="inline-flex bg-green-100 text-green-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-green-900 dark:text-green-300">
|
<dd class="inline-flex text-green-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded ">
|
||||||
{% translate 'Entregado' %}
|
{% translate 'Entregado' %}
|
||||||
</dd>
|
</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% elif order.status == 'ERR' %}
|
{% elif order.status == 'ERR' %}
|
||||||
<dd class="inline-flex bg-red-100 text-red-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-red-900 dark:text-red-300">
|
<dd class="inline-flex text-red-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded ">
|
||||||
{% translate 'Error' %}
|
{% translate 'Error' %}
|
||||||
</dd>
|
</dd>
|
||||||
{% elif order.status == 'RTN' %}
|
{% elif order.status == 'RTN' %}
|
||||||
<dd class="inline-flex bg-yellow-100 text-yellow-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-yellow-900 dark:text-yellow-300">
|
<dd class="inline-flex text-yellow-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded ">
|
||||||
{% translate 'Devuelto' %}
|
{% translate 'Devuelto' %}
|
||||||
</dd>
|
</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<a href="{% url 'web:order' uuid=order.uuid %}"
|
<a href="{% url 'web:order' uuid=order.uuid %}"
|
||||||
class="w-full inline-flex justify-center rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-primary-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700 lg:w-auto">
|
class="w-full inline-flex justify-center rounded-lg px-3 py-2 text-sm font-medium hover: hover:text-primary-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 : :text-white :ring-gray-700 lg:w-auto">
|
||||||
{% translate 'Ver pedido' %}
|
{% translate 'Ver pedido' %}
|
||||||
</a>
|
</a>
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
{% block main %}
|
{% block main %}
|
||||||
{% include 'components/generic/navbar.html' %}
|
{% include 'components/generic/navbar.html' %}
|
||||||
|
|
||||||
<section class="min-w-full py-8 bg-white md:py-16 antialiased">
|
<section class="min-w-full py-8 md:py-16 antialiased">
|
||||||
<div class="max-w-screen-xl px-4 mx-auto 2xl:px-0">
|
<div class="max-w-screen-xl px-4 mx-auto 2xl:px-0">
|
||||||
<div class="lg:grid lg:grid-cols-2 lg:gap-8 xl:gap-16">
|
<div class="lg:grid lg:grid-cols-2 lg:gap-8 xl:gap-16">
|
||||||
<div class="shrink-0 max-w-md lg:max-w-lg mx-auto">
|
<div class="shrink-0 max-w-md lg:max-w-lg mx-auto">
|
||||||
@@ -31,13 +31,13 @@
|
|||||||
|
|
||||||
<div class="my-4 sm:m-8 lg:m-0">
|
<div class="my-4 sm:m-8 lg:m-0">
|
||||||
|
|
||||||
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">
|
<h1 class="text-xl font-semibold sm:text-2xl ">
|
||||||
{{ product.name }}
|
{{ product.name }}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="my-4 sm:items-center sm:gap-4 sm:flex">
|
<div class="my-4 sm:items-center sm:gap-4 sm:flex">
|
||||||
<p
|
<p
|
||||||
class="text-2xl font-extrabold text-gray-900 sm:text-3xl "
|
class="text-2xl font-extrabold sm:text-3xl "
|
||||||
>
|
>
|
||||||
{{ product.price.price_with_tax }} €
|
{{ product.price.price_with_tax }} €
|
||||||
</p>
|
</p>
|
||||||
@@ -53,10 +53,10 @@
|
|||||||
|
|
||||||
{% include 'components/cart/add_to_cart.html' %}
|
{% include 'components/cart/add_to_cart.html' %}
|
||||||
|
|
||||||
<hr class="my-6 md:my-8 border-gray-200 dark:border-gray-800"/>
|
<hr class="my-6 md:my-8 "/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<p class="mb-6 text-gray-500 dark:text-gray-400">
|
<p class="mb-6 ">
|
||||||
{{ product.description }}
|
{{ product.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
>
|
>
|
||||||
<h1
|
<h1
|
||||||
class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl my-4"
|
class="text-xl font-semibold sm:text-2xl my-4"
|
||||||
>
|
>
|
||||||
{% translate 'Lista de deseados' %}
|
{% translate 'Lista de deseados' %}
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
+10
-10
@@ -14,34 +14,34 @@ class TestLogin(TestCase):
|
|||||||
self.user.save()
|
self.user.save()
|
||||||
|
|
||||||
def test_login(self):
|
def test_login(self):
|
||||||
response = self.client.post(reverse('web:login'), {'username': self.user.username, 'password': self.password})
|
response = self.client.post(reverse('users:login'), {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.url == reverse('web:index')
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
def test_login_get(self):
|
def test_login_get(self):
|
||||||
response = self.client.get(reverse('web:login'))
|
response = self.client.get(reverse('users:login'))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
def test_login_already_logged_in(self):
|
def test_login_already_logged_in(self):
|
||||||
response = self.client.post(reverse('web:login'), {'username': self.user.username, 'password': self.password})
|
response = self.client.post(reverse('users:login'), {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.url == reverse('web:index')
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
response = self.client.get(reverse('web:login'))
|
response = self.client.get(reverse('users:login'))
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.url == reverse('web:index')
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
def test_login_failed(self):
|
def test_login_failed(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('web:login'), {'username': self.user.username, 'password': 'wrongpassword'}
|
reverse('users:login'), {'username': self.user.username, 'password': 'wrongpassword'}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
||||||
def test_login_then_logout(self):
|
def test_login_then_logout(self):
|
||||||
response = self.client.post(reverse('web:login'), {'username': self.user.username, 'password': self.password})
|
response = self.client.post(reverse('users:login'), {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.url == reverse('web:index')
|
assert response.url == reverse('web:index')
|
||||||
@@ -56,7 +56,7 @@ class TestLogin(TestCase):
|
|||||||
assert response.url == reverse('web:index')
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
def test_login_then_get_logout(self):
|
def test_login_then_get_logout(self):
|
||||||
response = self.client.post(reverse('web:login'), {'username': self.user.username, 'password': self.password})
|
response = self.client.post(reverse('users:login'), {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.url == reverse('web:index')
|
assert response.url == reverse('web:index')
|
||||||
@@ -66,7 +66,7 @@ class TestLogin(TestCase):
|
|||||||
assert response.url == reverse('web:index')
|
assert response.url == reverse('web:index')
|
||||||
|
|
||||||
def test_login_then_get_my_account(self):
|
def test_login_then_get_my_account(self):
|
||||||
response = self.client.post(reverse('web:login'), {'username': self.user.username, 'password': self.password})
|
response = self.client.post(reverse('users:login'), {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.url == reverse('web:index')
|
assert response.url == reverse('web:index')
|
||||||
@@ -75,7 +75,7 @@ class TestLogin(TestCase):
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
def test_login_redirection_to_my_account(self):
|
def test_login_redirection_to_my_account(self):
|
||||||
url = f'{reverse("web:login")}?next={reverse("web:my_account")}'
|
url = f'{reverse("users:login")}?next={reverse("web:my_account")}'
|
||||||
response = self.client.post(url, {'username': self.user.username, 'password': self.password})
|
response = self.client.post(url, {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
@@ -86,7 +86,7 @@ class TestLogin(TestCase):
|
|||||||
assert response.url == reverse('web:my_account')
|
assert response.url == reverse('web:my_account')
|
||||||
|
|
||||||
def test_login_redirection_to_my_orders(self):
|
def test_login_redirection_to_my_orders(self):
|
||||||
url = f'{reverse("web:login")}?next={reverse("web:orders")}'
|
url = f'{reverse("users:login")}?next={reverse("web:orders")}'
|
||||||
response = self.client.post(url, {'username': self.user.username, 'password': self.password})
|
response = self.client.post(url, {'username': self.user.username, 'password': self.password})
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ class TestRegister(TransactionTestCase):
|
|||||||
self.last_name = 'The Lord of the Rings'
|
self.last_name = 'The Lord of the Rings'
|
||||||
|
|
||||||
def test_get_register_page(self):
|
def test_get_register_page(self):
|
||||||
response = self.client.get(reverse('web:register'))
|
response = self.client.get(reverse('users:register'))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
def test_create_user_account(self):
|
def test_create_user_account(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('web:register'),
|
reverse('users:register'),
|
||||||
{
|
{
|
||||||
'email': self.email,
|
'email': self.email,
|
||||||
'password1': self.password,
|
'password1': self.password,
|
||||||
@@ -35,11 +35,11 @@ class TestRegister(TransactionTestCase):
|
|||||||
assert user is not None
|
assert user is not None
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.url == reverse('web:login')
|
assert response.url == reverse('users:login')
|
||||||
|
|
||||||
def test_create_user_account_distinct_password(self):
|
def test_create_user_account_distinct_password(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('web:register'),
|
reverse('users:register'),
|
||||||
{
|
{
|
||||||
'email': self.email,
|
'email': self.email,
|
||||||
'password1': self.password,
|
'password1': self.password,
|
||||||
@@ -57,7 +57,7 @@ class TestRegister(TransactionTestCase):
|
|||||||
|
|
||||||
def test_create_user_account_no_first_name(self):
|
def test_create_user_account_no_first_name(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('web:register'),
|
reverse('users:register'),
|
||||||
{
|
{
|
||||||
'email': self.email,
|
'email': self.email,
|
||||||
'password1': self.password,
|
'password1': self.password,
|
||||||
@@ -75,7 +75,7 @@ class TestRegister(TransactionTestCase):
|
|||||||
|
|
||||||
def test_create_user_account_no_last_name(self):
|
def test_create_user_account_no_last_name(self):
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('web:register'),
|
reverse('users:register'),
|
||||||
{
|
{
|
||||||
'email': self.email,
|
'email': self.email,
|
||||||
'password1': self.password,
|
'password1': self.password,
|
||||||
@@ -95,7 +95,7 @@ class TestRegister(TransactionTestCase):
|
|||||||
assert User.objects.all().count() == 0
|
assert User.objects.all().count() == 0
|
||||||
User.objects.create_user(email=self.email, username=self.email)
|
User.objects.create_user(email=self.email, username=self.email)
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('web:register'),
|
reverse('users:register'),
|
||||||
{
|
{
|
||||||
'email': self.email,
|
'email': self.email,
|
||||||
'password1': self.password,
|
'password1': self.password,
|
||||||
|
|||||||
@@ -20,26 +20,26 @@ class TestResetPassword(TransactionTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_get_reset_password_page(self):
|
def test_get_reset_password_page(self):
|
||||||
response = self.client.get(reverse('web:reset_password'))
|
response = self.client.get(reverse('users:reset_password'))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
def test_reset_password(self):
|
def test_reset_password(self):
|
||||||
response = self.client.post(reverse('web:reset_password'), {'email': self.email})
|
response = self.client.post(reverse('users:reset_password'), {'email': self.email})
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.url == reverse('web:reset_password_email_sent')
|
assert response.url == reverse('users:reset_password_email_sent')
|
||||||
|
|
||||||
def test_reset_password_not_existing_user(self):
|
def test_reset_password_not_existing_user(self):
|
||||||
response = self.client.post(reverse('web:reset_password'), {'email': 'vanpiro@noesiten.com'})
|
response = self.client.post(reverse('users:reset_password'), {'email': 'vanpiro@noesiten.com'})
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.url == reverse('web:reset_password_email_sent')
|
assert response.url == reverse('users:reset_password_email_sent')
|
||||||
|
|
||||||
def test_reset_password_confirm_get(self):
|
def test_reset_password_confirm_get(self):
|
||||||
token = default_token_generator.make_token(self.user)
|
token = default_token_generator.make_token(self.user)
|
||||||
uidb64 = urlsafe_base64_encode(force_bytes(self.user.pk))
|
uidb64 = urlsafe_base64_encode(force_bytes(self.user.pk))
|
||||||
|
|
||||||
response = self.client.get(reverse('web:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}))
|
response = self.client.get(reverse('users:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}))
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
@@ -51,11 +51,11 @@ class TestResetPassword(TransactionTestCase):
|
|||||||
new_password = '89733wy29'
|
new_password = '89733wy29'
|
||||||
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('web:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}),
|
reverse('users:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}),
|
||||||
{'token': form_token, 'new_password1': new_password, 'new_password2': new_password},
|
{'token': form_token, 'new_password1': new_password, 'new_password2': new_password},
|
||||||
)
|
)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.url == reverse('web:login')
|
assert response.url == reverse('users:login')
|
||||||
self.user.refresh_from_db()
|
self.user.refresh_from_db()
|
||||||
|
|
||||||
assert self.user.check_password(new_password)
|
assert self.user.check_password(new_password)
|
||||||
@@ -68,7 +68,7 @@ class TestResetPassword(TransactionTestCase):
|
|||||||
new_password = '89733wy29'
|
new_password = '89733wy29'
|
||||||
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('web:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}),
|
reverse('users:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}),
|
||||||
{'token': form_token, 'new_password1': new_password, 'new_password2': 'otherpassw13'},
|
{'token': form_token, 'new_password1': new_password, 'new_password2': 'otherpassw13'},
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@@ -81,7 +81,7 @@ class TestResetPassword(TransactionTestCase):
|
|||||||
new_password = '89733wy29'
|
new_password = '89733wy29'
|
||||||
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse('web:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}),
|
reverse('users:reset_password_confirm', kwargs={'uidb64': uidb64, 'token': token}),
|
||||||
{'token': form_token, 'new_password1': new_password, 'new_password2': new_password},
|
{'token': form_token, 'new_password1': new_password, 'new_password2': new_password},
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|||||||
+1
-17
@@ -14,15 +14,6 @@ from web.views.components import (
|
|||||||
wishlist_button,
|
wishlist_button,
|
||||||
change_password_component,
|
change_password_component,
|
||||||
)
|
)
|
||||||
from web.views.users import (
|
|
||||||
login,
|
|
||||||
logout,
|
|
||||||
my_account,
|
|
||||||
register,
|
|
||||||
reset_password,
|
|
||||||
reset_password_confirm,
|
|
||||||
reset_password_email_sent,
|
|
||||||
)
|
|
||||||
from web.views.web import (
|
from web.views.web import (
|
||||||
add_cart_item,
|
add_cart_item,
|
||||||
add_to_wishlist,
|
add_to_wishlist,
|
||||||
@@ -48,14 +39,7 @@ i18n_resolvers = i18n_patterns(
|
|||||||
path(_('cart/'), cart_detail, name='cart_detail'),
|
path(_('cart/'), cart_detail, name='cart_detail'),
|
||||||
path(_('orders/'), login_required(orders, login_url=_('/login/')), name='orders'),
|
path(_('orders/'), login_required(orders, login_url=_('/login/')), name='orders'),
|
||||||
path(_('order/<str:uuid>/'), order_detail, name='order'),
|
path(_('order/<str:uuid>/'), order_detail, name='order'),
|
||||||
# users
|
|
||||||
path(_('login/'), login, name='login'),
|
|
||||||
path(_('logout/'), logout, name='logout'),
|
|
||||||
path(_('register/'), register, name='register'),
|
|
||||||
path(_('reset-password/'), reset_password, name='reset_password'),
|
|
||||||
path(_('reset-password/<uidb64>/<token>/'), reset_password_confirm, name='reset_password_confirm'),
|
|
||||||
path(_('reset-password/email-sent/'), reset_password_email_sent, name='reset_password_email_sent'),
|
|
||||||
path(_('my-account/'), login_required(my_account, login_url=_('/login/')), name='my_account'),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|||||||
+3
-3
@@ -71,7 +71,7 @@ class LoginView(View, RedirectionMixin):
|
|||||||
|
|
||||||
class RegisterView(TemplateView, RedirectionMixin):
|
class RegisterView(TemplateView, RedirectionMixin):
|
||||||
template_name = 'users/register.html'
|
template_name = 'users/register.html'
|
||||||
redirect_to = 'web:login'
|
redirect_to = 'users:login'
|
||||||
form_class = RegisterForm
|
form_class = RegisterForm
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
@@ -123,7 +123,7 @@ class LogoutView(View, RedirectionMixin):
|
|||||||
class ResetPasswordView(TemplateView):
|
class ResetPasswordView(TemplateView):
|
||||||
template_name = 'users/reset_password.html'
|
template_name = 'users/reset_password.html'
|
||||||
form_class = PasswordResetForm
|
form_class = PasswordResetForm
|
||||||
redirect_to = 'web:reset_password_email_sent'
|
redirect_to = 'users:reset_password_email_sent'
|
||||||
html_reset_password_template_name = 'mails/reset_password.html'
|
html_reset_password_template_name = 'mails/reset_password.html'
|
||||||
subject_template_name = 'mails/subject_reset_password.txt'
|
subject_template_name = 'mails/subject_reset_password.txt'
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ class ResetPasswordEmailSent(TemplateView):
|
|||||||
class ResetPasswordConfirmView(TemplateView):
|
class ResetPasswordConfirmView(TemplateView):
|
||||||
template_name = 'users/reset_password_confirm.html'
|
template_name = 'users/reset_password_confirm.html'
|
||||||
form_class = SetPasswordForm
|
form_class = SetPasswordForm
|
||||||
redirect_to = 'web:login'
|
redirect_to = 'users:login'
|
||||||
token_generator = default_token_generator
|
token_generator = default_token_generator
|
||||||
|
|
||||||
def get_user(self):
|
def get_user(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user