diff --git a/backend/account/admin.py b/backend/account/admin.py index 26e8d99..4beb386 100644 --- a/backend/account/admin.py +++ b/backend/account/admin.py @@ -2,8 +2,28 @@ from django.contrib import admin from .models import * from unfold.admin import ModelAdmin +from import_export.admin import ImportExportModelAdmin +from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm +from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget +from django.contrib.postgres.fields import ArrayField @admin.register(User) -class UserAdmin(ModelAdmin): +class UserAdmin(ModelAdmin, ImportExportModelAdmin): + list_display = ['phone', 'email', 'is_superuser'] - readonly_fields = ['password', 'last_login', 'otp_expiry', 'otp_hash'] \ No newline at end of file + readonly_fields = ['phone'] + + exclude = ('otp_hash', 'otp_expiry', 'is_active', 'is_staff', 'password', 'last_login') + import_form_class = ImportForm + export_form_class = ExportForm + + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } + \ No newline at end of file diff --git a/backend/account/migrations/0001_initial.py b/backend/account/migrations/0001_initial.py index 98da48a..88ed6fd 100644 --- a/backend/account/migrations/0001_initial.py +++ b/backend/account/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.2 on 2025-01-27 18:07 +# Generated by Django 5.1.2 on 2025-01-28 17:00 import django.db.models.deletion from django.conf import settings diff --git a/backend/chat/admin.py b/backend/chat/admin.py index 63ad8f7..8d83c8f 100644 --- a/backend/chat/admin.py +++ b/backend/chat/admin.py @@ -2,7 +2,24 @@ from django.contrib import admin from .models import * from unfold.admin import ModelAdmin +from import_export.admin import ImportExportModelAdmin +from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm +from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget +from django.contrib.postgres.fields import ArrayField + @admin.register(ProductChatModel) -class ProductChatAdmin(ModelAdmin): - pass \ No newline at end of file +class ProductChatAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + readonly_fields = ('user', 'product', 'thread') + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } diff --git a/backend/chat/migrations/0001_initial.py b/backend/chat/migrations/0001_initial.py index 40f2f7c..60a0a88 100644 --- a/backend/chat/migrations/0001_initial.py +++ b/backend/chat/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.2 on 2025-01-27 18:07 +# Generated by Django 5.1.2 on 2025-01-28 17:00 import django.db.models.deletion from django.conf import settings diff --git a/backend/core/settings.py b/backend/core/settings.py index 65a2e8d..7595fbe 100644 --- a/backend/core/settings.py +++ b/backend/core/settings.py @@ -27,13 +27,13 @@ EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD") DEFAULT_FROM_EMAIL = os.getenv("SECRET_KEY") SECRET_KEY = os.getenv("SECRET_KEY") -DEBUG = False +DEBUG = True # in production lists of allowed hosts and allowed orgins will genrate # in development every host and orgin will be true # in prodcution it will use the postgres info you enterd in .env.local # in development it will use the sqlite BASE_DIR = Path(__file__).resolve().parent.parent -if not DEBUG: +if DEBUG: ALLOWED_HOSTS = ['127.0.0.1', 'localhost', DOMAIN, API_DOMAIN] CSRF_TRUSTED_ORIGINS = [ f"https://{DOMAIN}", @@ -103,6 +103,7 @@ INSTALLED_APPS = [ 'rest_framework_simplejwt', 'rest_framework_simplejwt.token_blacklist', 'rest_framework.authtoken', + 'import_export', # custom apps 'product', 'account', diff --git a/backend/home/admin.py b/backend/home/admin.py index 173a572..08614ce 100644 --- a/backend/home/admin.py +++ b/backend/home/admin.py @@ -2,11 +2,38 @@ from django.contrib import admin from .models import * from unfold.admin import ModelAdmin +from import_export.admin import ImportExportModelAdmin +from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm +from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget +from django.contrib.postgres.fields import ArrayField + @admin.register(SliderModel) -class SliderAdmin(ModelAdmin): - pass +class SliderAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + + compressed_fields = False + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } @admin.register(HomeImageModel) -class HomeImageAdmin(ModelAdmin): - pass \ No newline at end of file +class HomeImageAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } \ No newline at end of file diff --git a/backend/home/migrations/0001_initial.py b/backend/home/migrations/0001_initial.py index 397620a..9369e7d 100644 --- a/backend/home/migrations/0001_initial.py +++ b/backend/home/migrations/0001_initial.py @@ -1,6 +1,5 @@ -# Generated by Django 5.1.2 on 2025-01-27 18:07 +# Generated by Django 5.1.2 on 2025-01-28 17:00 -import django.db.models.deletion from django.db import migrations, models @@ -9,18 +8,33 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('product', '0001_initial'), ] operations = [ + migrations.CreateModel( + name='HomeImageModel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image1', models.ImageField(upload_to='diff_image/')), + ('image2', models.ImageField(upload_to='diff_image/')), + ('title1', models.CharField(max_length=50)), + ('title2', models.CharField(max_length=50)), + ('description1', models.TextField()), + ('description2', models.TextField()), + ('link1', models.URLField()), + ('link2', models.URLField()), + ('unique_filed', models.CharField(choices=[('unique', 'unique')], default='unique', max_length=20, unique=True)), + ], + ), migrations.CreateModel( name='SliderModel', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('link', models.URLField(verbose_name='لینک')), ('title', models.CharField(max_length=50, verbose_name='عنوان')), + ('description', models.TextField(verbose_name='توضیحات')), ('image', models.ImageField(blank=True, null=True, upload_to='slider_image/', verbose_name='عکس اسلایدر')), ('video', models.FileField(blank=True, null=True, upload_to='slider_video/', verbose_name='ویدیواسلایدر')), - ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='product.productmodel', verbose_name='محصول')), ], options={ 'verbose_name': 'اسلایدر', diff --git a/backend/home/migrations/0002_remove_slidermodel_product_slidermodel_description_and_more.py b/backend/home/migrations/0002_remove_slidermodel_product_slidermodel_description_and_more.py deleted file mode 100644 index a72f609..0000000 --- a/backend/home/migrations/0002_remove_slidermodel_product_slidermodel_description_and_more.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 5.1.2 on 2025-01-27 18:15 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('home', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='slidermodel', - name='product', - ), - migrations.AddField( - model_name='slidermodel', - name='description', - field=models.TextField(default='', verbose_name='توضیحات'), - preserve_default=False, - ), - migrations.AddField( - model_name='slidermodel', - name='link', - field=models.URLField(default='', verbose_name='لینک'), - preserve_default=False, - ), - ] diff --git a/backend/home/migrations/0003_homeimagemodel.py b/backend/home/migrations/0003_homeimagemodel.py deleted file mode 100644 index 471577b..0000000 --- a/backend/home/migrations/0003_homeimagemodel.py +++ /dev/null @@ -1,26 +0,0 @@ -# Generated by Django 5.1.2 on 2025-01-27 18:31 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('home', '0002_remove_slidermodel_product_slidermodel_description_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='HomeImageModel', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('image1', models.ImageField(upload_to='diff_image/')), - ('image2', models.ImageField(upload_to='diff_image/')), - ('title1', models.CharField(max_length=50)), - ('title2', models.CharField(max_length=50)), - ('description1', models.TextField()), - ('description2', models.TextField()), - ('unique_filed', models.CharField(choices=[('unique', 'unique')], default='unique', max_length=20, unique=True)), - ], - ), - ] diff --git a/backend/home/migrations/0004_homeimagemodel_link1_homeimagemodel_link2.py b/backend/home/migrations/0004_homeimagemodel_link1_homeimagemodel_link2.py deleted file mode 100644 index 5eaa27d..0000000 --- a/backend/home/migrations/0004_homeimagemodel_link1_homeimagemodel_link2.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 5.1.2 on 2025-01-27 18:33 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('home', '0003_homeimagemodel'), - ] - - operations = [ - migrations.AddField( - model_name='homeimagemodel', - name='link1', - field=models.URLField(default=''), - preserve_default=False, - ), - migrations.AddField( - model_name='homeimagemodel', - name='link2', - field=models.URLField(default=''), - preserve_default=False, - ), - ] diff --git a/backend/order/admin.py b/backend/order/admin.py index 8c38f3f..e0dc463 100644 --- a/backend/order/admin.py +++ b/backend/order/admin.py @@ -1,3 +1,37 @@ from django.contrib import admin +from .models import * +from unfold.admin import ModelAdmin, TabularInline -# Register your models here. +from import_export.admin import ImportExportModelAdmin +from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm +from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget +from django.contrib.postgres.fields import ArrayField + + +class OrderItemModelInline(TabularInline): + model = OrderItemModel + extra = 0 + max_num = 0 + def has_delete_permission(self, request, obj=None): + return False + def get_readonly_fields(self, request, obj=None): + return [field.name for field in self.model._meta.fields] + + + + +@admin.register(OrderModel) +class OrderAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } + inlines = [OrderItemModelInline] \ No newline at end of file diff --git a/backend/order/migrations/0001_initial.py b/backend/order/migrations/0001_initial.py index 545e2b3..1435563 100644 --- a/backend/order/migrations/0001_initial.py +++ b/backend/order/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.2 on 2025-01-27 18:07 +# Generated by Django 5.1.2 on 2025-01-28 17:00 import django.db.models.deletion from django.conf import settings diff --git a/backend/product/admin.py b/backend/product/admin.py index b1f3efd..5514d08 100644 --- a/backend/product/admin.py +++ b/backend/product/admin.py @@ -2,23 +2,91 @@ from django.contrib import admin from .models import * from unfold.admin import ModelAdmin +from import_export.admin import ImportExportModelAdmin +from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm +from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget +from django.contrib.postgres.fields import ArrayField + @admin.register(ProductModel) -class ProductModelAdmin(ModelAdmin): - pass +class ProductModelAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + readonly_fields = ('slug', ) + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + models.TextField: { + "widget": WysiwygWidget, + }, + ArrayField: { + "widget": ArrayWidget, + } + } @admin.register(MainCategoryModel) -class MainCategoryModelAdmin(ModelAdmin): - pass +class MainCategoryModelAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + readonly_fields = ('slug', ) + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } @admin.register(SubCategoryModel) -class SubCategoryModelAdmin(ModelAdmin): - pass +class SubCategoryModelAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + readonly_fields = ('slug', ) + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } @admin.register(CommentModel) -class CommentAdmin(ModelAdmin): - pass +class CommentAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } @admin.register(DollorModel) -class DollorAdmin(ModelAdmin): +class DollorAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + exclude = ('unique_filed', ) + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } readonly_fields = ('price',) \ No newline at end of file diff --git a/backend/product/migrations/0001_initial.py b/backend/product/migrations/0001_initial.py index 8821b93..db94f0b 100644 --- a/backend/product/migrations/0001_initial.py +++ b/backend/product/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.2 on 2025-01-27 18:07 +# Generated by Django 5.1.2 on 2025-01-28 17:00 import django.db.models.deletion from django.conf import settings @@ -81,7 +81,12 @@ class Migration(migrations.Migration): migrations.CreateModel( name='SubCategoryModel', fields=[ - ('maincategorymodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='product.maincategorymodel')), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=50, verbose_name='نام')), + ('slug', models.SlugField(help_text='اسم دسته را برای مسیر به انگلیسی و بدون فاصله وارد کنید', unique=True)), + ('icon', models.ImageField(blank=True, null=True, upload_to='category_model/', verbose_name='آیکون')), + ('meta_title', models.CharField(blank=True, help_text='عنوان متا برای SEO', max_length=60, null=True, verbose_name='عنوان متا')), + ('meta_description', models.TextField(blank=True, help_text='توضیحات متا برای SEO', max_length=160, null=True, verbose_name='توضیحات متا')), ('show', models.BooleanField(default=False, verbose_name='نمایش در خانه')), ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='subcategorys', to='product.maincategorymodel', verbose_name='دسته\u200cبندی والد')), ], @@ -89,7 +94,6 @@ class Migration(migrations.Migration): 'verbose_name': 'زیر دسته\u200cبندی', 'verbose_name_plural': 'زیر دسته\u200cبندی\u200cها', }, - bases=('product.maincategorymodel',), ), migrations.AddField( model_name='productmodel', diff --git a/backend/product/migrations/0002_rename_icon_subcategorymodel_image.py b/backend/product/migrations/0002_rename_icon_subcategorymodel_image.py new file mode 100644 index 0000000..4d143cb --- /dev/null +++ b/backend/product/migrations/0002_rename_icon_subcategorymodel_image.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.2 on 2025-01-28 17:48 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0001_initial'), + ] + + operations = [ + migrations.RenameField( + model_name='subcategorymodel', + old_name='icon', + new_name='image', + ), + ] diff --git a/backend/product/migrations/0003_subcategorymodel_icon_alter_subcategorymodel_image.py b/backend/product/migrations/0003_subcategorymodel_icon_alter_subcategorymodel_image.py new file mode 100644 index 0000000..56fe281 --- /dev/null +++ b/backend/product/migrations/0003_subcategorymodel_icon_alter_subcategorymodel_image.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.2 on 2025-01-28 17:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0002_rename_icon_subcategorymodel_image'), + ] + + operations = [ + migrations.AddField( + model_name='subcategorymodel', + name='icon', + field=models.ImageField(blank=True, null=True, upload_to='category_model/', verbose_name='آیکون'), + ), + migrations.AlterField( + model_name='subcategorymodel', + name='image', + field=models.ImageField(blank=True, null=True, upload_to='category_model/', verbose_name='عکس'), + ), + ] diff --git a/backend/product/migrations/0004_alter_subcategorymodel_parent.py b/backend/product/migrations/0004_alter_subcategorymodel_parent.py new file mode 100644 index 0000000..d331c23 --- /dev/null +++ b/backend/product/migrations/0004_alter_subcategorymodel_parent.py @@ -0,0 +1,20 @@ +# Generated by Django 5.1.2 on 2025-01-28 18:53 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0003_subcategorymodel_icon_alter_subcategorymodel_image'), + ] + + operations = [ + migrations.AlterField( + model_name='subcategorymodel', + name='parent', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='subcategorys', to='product.maincategorymodel', verbose_name='دسته\u200cبندی والد'), + preserve_default=False, + ), + ] diff --git a/backend/product/models.py b/backend/product/models.py index bca4739..b0a9dd6 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -19,16 +19,32 @@ class MainCategoryModel(models.Model): def __str__(self): return self.name - # def get_absolute_url(self): - # return reverse('category_detail', kwargs={'slug': self.slug}) + def save(self, *args, **kwargs): + if not self.slug: + self.slug = slugify(self.name, allow_unicode=True) + super().save(*args, **kwargs) -class SubCategoryModel(MainCategoryModel): - parent = models.ForeignKey(MainCategoryModel, on_delete=models.CASCADE, related_name='subcategorys', null=True, blank=True, verbose_name='دسته‌بندی والد') +class SubCategoryModel(models.Model): + name = models.CharField(max_length=50, verbose_name='نام') + slug = models.SlugField(max_length=50, unique=True, help_text="اسم دسته را برای مسیر به انگلیسی و بدون فاصله وارد کنید") + image = models.ImageField(upload_to='category_model/',verbose_name='عکس', blank=True, null=True) + icon = models.ImageField(upload_to='category_model/',verbose_name='آیکون', blank=True, null=True) + meta_title = models.CharField(max_length=60, verbose_name="عنوان متا", help_text="عنوان متا برای SEO", blank=True, null=True) + meta_description = models.TextField(max_length=160, verbose_name="توضیحات متا", help_text="توضیحات متا برای SEO", blank=True, null=True) + parent = models.ForeignKey(MainCategoryModel, on_delete=models.CASCADE, related_name='subcategorys', verbose_name='دسته‌بندی والد') show = models.BooleanField(default=False, verbose_name='نمایش در خانه') + class Meta: verbose_name = "زیر دسته‌بندی" verbose_name_plural = "زیر دسته‌بندی‌ها" + + def __str__(self): + return self.name + def save(self, *args, **kwargs): + if not self.slug: + self.slug = slugify(self.name, allow_unicode=True) + super().save(*args, **kwargs) class DollorModel(models.Model): price = models.FloatField(null=True, blank=True, verbose_name='قیمت دلار') diff --git a/backend/product/serializers.py b/backend/product/serializers.py index c331bb7..12e25f4 100644 --- a/backend/product/serializers.py +++ b/backend/product/serializers.py @@ -37,11 +37,14 @@ class CommentSerializer(serializers.ModelSerializer): class SubCategorySerializer(serializers.ModelSerializer): product_count = serializers.SerializerMethodField() + parent = serializers.SerializerMethodField() class Meta: model = SubCategoryModel - fields = ['id', 'name', 'slug','icon', 'meta_title', 'meta_description', 'product_count', 'show'] + fields = ['id', 'name', 'slug','icon', 'meta_title', 'meta_description', 'product_count', 'show', 'parent', 'image'] def get_product_count(self, obj): return obj.products.count() + def get_parent(self, obj): + return obj.parent.name class MainCategorySerializer(serializers.ModelSerializer): diff --git a/backend/product/views.py b/backend/product/views.py index 05ee93d..3538c5c 100644 --- a/backend/product/views.py +++ b/backend/product/views.py @@ -56,7 +56,7 @@ class ProductView(APIView): product = get_object_or_404(ProductModel, id=pk) dollor_object, _ = DollorModel.objects.get_or_create(unique_filed='unique') dollor_price = dollor_object.price - product_ser = self.serializer_class(instance=product, many=False, context={'dollor_price': dollor_price}) + product_ser = self.serializer_class(instance=product, many=False, context={'dollor_price': dollor_price, 'request': request}) return Response(product_ser.data, status=status.HTTP_200_OK) diff --git a/backend/ticket/admin.py b/backend/ticket/admin.py index 8c38f3f..77e9db3 100644 --- a/backend/ticket/admin.py +++ b/backend/ticket/admin.py @@ -1,3 +1,46 @@ from django.contrib import admin +from .models import * +from unfold.admin import ModelAdmin, TabularInline -# Register your models here. +from import_export.admin import ImportExportModelAdmin +from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm +from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget +from django.contrib.postgres.fields import ArrayField + +class MessageInline(TabularInline): + model = Message + extra = 1 + +@admin.register(Ticket) +class TicketAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } + inlines = [MessageInline] + +@admin.register(Message) +class MessageAdmin(ModelAdmin, ImportExportModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + + + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + models.TextField: { + "widget": WysiwygWidget, + }, + ArrayField: { + "widget": ArrayWidget, + } + } \ No newline at end of file diff --git a/backend/ticket/migrations/0001_initial.py b/backend/ticket/migrations/0001_initial.py index 1610102..01683ad 100644 --- a/backend/ticket/migrations/0001_initial.py +++ b/backend/ticket/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.2 on 2025-01-27 18:07 +# Generated by Django 5.1.2 on 2025-01-28 17:00 import django.db.models.deletion from django.conf import settings @@ -19,7 +19,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('subject', models.CharField(max_length=255)), - ('status', models.CharField(choices=[('open', 'Open'), ('in_progress', 'In Progress'), ('resolved', 'Resolved'), ('closed', 'Closed')], default='open', max_length=20)), + ('status', models.CharField(choices=[('open', 'یاز'), ('in_progress', 'در حال پردازش'), ('resolved', 'حل شده'), ('closed', 'باز')], default='open', max_length=20)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('admin', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_tickets', to=settings.AUTH_USER_MODEL)), diff --git a/backend/ticket/models.py b/backend/ticket/models.py index 7bc0120..15b03da 100644 --- a/backend/ticket/models.py +++ b/backend/ticket/models.py @@ -3,10 +3,10 @@ from account.models import User class Ticket(models.Model): STATUS_CHOICES = [ - ('open', 'Open'), - ('in_progress', 'In Progress'), - ('resolved', 'Resolved'), - ('closed', 'Closed'), + ('open', 'یاز'), + ('in_progress', 'در حال پردازش'), + ('resolved', 'حل شده'), + ('closed', 'باز'), ] subject = models.CharField(max_length=255) diff --git a/frontend/components/global/CategoryCard.vue b/frontend/components/global/CategoryCard.vue index ce29d50..9948f97 100644 --- a/frontend/components/global/CategoryCard.vue +++ b/frontend/components/global/CategoryCard.vue @@ -23,7 +23,7 @@ const { colorObject } = useImageColor(`#category-image-${id.value}`); diff --git a/frontend/components/global/Header.vue b/frontend/components/global/Header.vue index 4fb8a3a..f02b0a3 100644 --- a/frontend/components/global/Header.vue +++ b/frontend/components/global/Header.vue @@ -3,7 +3,6 @@ import useGetAccount from "~/composables/api/account/useGetAccount"; import { useAuth } from "~/composables/api/auth/useAuth"; -import useBaseUrl from "~/composables/global/useBaseUrl"; // types @@ -16,20 +15,19 @@ type NavLink = { const { data: account } = useGetAccount(); const { logout } = useAuth(); -const baseUrl = useBaseUrl(); const nav_links = ref([ { - title: "فروشگاه", - path: "#", + title: "خانه", + path: "/", + }, + { + title: "محصولات", + path: "/products", }, { title: "دسته بندی ها", - path: "#", - }, - { - title: "جستجو", - path: "#", + path: "/category", }, { title: "ارتباط با ما", @@ -53,28 +51,32 @@ const nav_links = ref([ v-if="!!account" :title="account.first_name + ' ' + account.last_name" @click="() => logout(true)" - class="size-[1.5rem] relative overflow-hidden rounded-full bg-slate-300" + class="size-[1.6rem] flex items-center justify-center relative overflow-hidden rounded-full bg-slate-300" > - + + + + - @@ -93,7 +95,23 @@ const nav_links = ref([ -
LOGO
+
+ + + + +
diff --git a/frontend/components/global/LoadingIndicator.vue b/frontend/components/global/LoadingIndicator.vue new file mode 100644 index 0000000..b82349b --- /dev/null +++ b/frontend/components/global/LoadingIndicator.vue @@ -0,0 +1,49 @@ + + + + + \ No newline at end of file diff --git a/frontend/components/global/Rate.vue b/frontend/components/global/Rate.vue index fdc5520..be6e1c4 100644 --- a/frontend/components/global/Rate.vue +++ b/frontend/components/global/Rate.vue @@ -1,6 +1,22 @@ + + \ No newline at end of file diff --git a/frontend/components/global/ServiceHighlights.vue b/frontend/components/global/ServiceHighlights.vue index fa7cf11..9206028 100644 --- a/frontend/components/global/ServiceHighlights.vue +++ b/frontend/components/global/ServiceHighlights.vue @@ -13,23 +13,23 @@ const highlights = ref([ { icon: "ci:headset", title: "خدمات مشتری", - description: "پشتیبانی استثنایی، راه‌حل‌های پایدار", + description: "پشتیبانی استثنایی، راه‌حل‌های پایدار برای شما عزیزان" }, { icon: "ci:delivery", title: "ارسال سریع و رایگان", - description: "ارسال رایگان برای سفارش‌های بالای ۱۵۰ دلار", + description: "ارسال رایگان برای سفارش‌های بالای ۱۵۰ دلار و خورده" }, { icon: "ci:users", title: "معرفی به دوستان", - description: "دوستان خود را معرفی کنید و هر دو ۱۵٪ تخفیف بگیرید", + description: "دوستان خود را معرفی کنید و هر دو ۱۵٪ تخفیف بگیرید" }, { icon: "ci:shield-done", title: "پرداخت امن", - description: "اطلاعات پرداخت شما به‌صورت امن پردازش می‌شود", - }, + description: "اطلاعات پرداخت شما به‌صورت امن پردازش می‌شود" + } ]); @@ -38,13 +38,13 @@ const highlights = ref([
\ No newline at end of file + diff --git a/frontend/components/product/ProductComments.vue b/frontend/components/product/ProductComments.vue index 15c2611..4bc9a08 100644 --- a/frontend/components/product/ProductComments.vue +++ b/frontend/components/product/ProductComments.vue @@ -3,7 +3,7 @@