diff --git a/backend/Pipfile b/backend/Pipfile index 486997f..0bc2492 100644 --- a/backend/Pipfile +++ b/backend/Pipfile @@ -9,6 +9,7 @@ djangorestframework = "*" python-dotenv = "*" psycopg2 = "*" pillow = "*" +transliterate = "*" [dev-packages] diff --git a/backend/Pipfile.lock b/backend/Pipfile.lock index 671f725..b0fee4a 100644 --- a/backend/Pipfile.lock +++ b/backend/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "8058db5f6e1f333af30cffe6634e7d018110d8c2fc6601f3a9c84a72c2ac3110" + "sha256": "c254f2788ffdf030b1b0fbe90f05c0c47f93704170c42e2607f2a77b22f6ede2" }, "pipfile-spec": 6, "requires": { @@ -156,6 +156,14 @@ "markers": "python_version >= '3.9'", "version": "==1.1.0" }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.17.0" + }, "sqlparse": { "hashes": [ "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272", @@ -163,6 +171,14 @@ ], "markers": "python_version >= '3.8'", "version": "==0.5.3" + }, + "transliterate": { + "hashes": [ + "sha256:010a5021bf6021689c4fade0985f3f7b3db1f2f16a48a09a56797f171c08ed42", + "sha256:bc608e0d48e687db9c2b1d7ea7c381afe0d1849cad216087d8e03d8d06a57c85" + ], + "index": "pypi", + "version": "==1.10.2" } }, "develop": {} diff --git a/backend/routes/migrations/0003_alter_route_owner_type.py b/backend/routes/migrations/0003_alter_route_owner_type.py new file mode 100644 index 0000000..1606587 --- /dev/null +++ b/backend/routes/migrations/0003_alter_route_owner_type.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.1 on 2025-05-15 16:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('routes', '0002_route'), + ] + + operations = [ + migrations.AlterField( + model_name='route', + name='owner_type', + field=models.CharField(choices=[('customer', 'Заказчик'), ('mover', 'Перевозчик')], default='customer', verbose_name='Тип операции'), + ), + ] diff --git a/backend/routes/models.py b/backend/routes/models.py index a1bff61..11683e3 100644 --- a/backend/routes/models.py +++ b/backend/routes/models.py @@ -64,7 +64,7 @@ class City(models.Model): class Route(models.Model): owner_type = models.CharField( - choices=owner_type_choices, default='customer', verbose_name=('Тип опреации')) + choices=owner_type_choices, default='customer', verbose_name=('Тип операции')) type_transport = models.CharField( choices=type_transport_choices, default='', verbose_name=('Выберите способ перевозки'), diff --git a/backend/sitemanagement/admin.py b/backend/sitemanagement/admin.py index fa06e5c..fb05e7b 100644 --- a/backend/sitemanagement/admin.py +++ b/backend/sitemanagement/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin -from .models import FAQ +from .models import * admin.site.register(FAQ) +admin.site.register(News) diff --git a/backend/sitemanagement/migrations/0002_news.py b/backend/sitemanagement/migrations/0002_news.py new file mode 100644 index 0000000..1efc771 --- /dev/null +++ b/backend/sitemanagement/migrations/0002_news.py @@ -0,0 +1,27 @@ +# Generated by Django 5.2.1 on 2025-05-15 16:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sitemanagement', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='News', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('titleImage', models.ImageField(upload_to='')), + ('title', models.CharField(max_length=100)), + ('content', models.CharField(max_length=1000)), + ], + options={ + 'verbose_name': 'Новость', + 'verbose_name_plural': 'Новости', + 'ordering': ['id'], + }, + ), + ] diff --git a/backend/sitemanagement/migrations/0003_alter_news_content_alter_news_title_and_more.py b/backend/sitemanagement/migrations/0003_alter_news_content_alter_news_title_and_more.py new file mode 100644 index 0000000..38f7a78 --- /dev/null +++ b/backend/sitemanagement/migrations/0003_alter_news_content_alter_news_title_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.1 on 2025-05-15 16:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sitemanagement', '0002_news'), + ] + + operations = [ + migrations.AlterField( + model_name='news', + name='content', + field=models.TextField(max_length=1000, verbose_name='Контент статьи'), + ), + migrations.AlterField( + model_name='news', + name='title', + field=models.CharField(max_length=100, verbose_name='Заголовок'), + ), + migrations.AlterField( + model_name='news', + name='titleImage', + field=models.ImageField(upload_to='', verbose_name='Главная картинка'), + ), + ] diff --git a/backend/sitemanagement/migrations/0004_news_slug.py b/backend/sitemanagement/migrations/0004_news_slug.py new file mode 100644 index 0000000..7f7b4f2 --- /dev/null +++ b/backend/sitemanagement/migrations/0004_news_slug.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.1 on 2025-05-15 16:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sitemanagement', '0003_alter_news_content_alter_news_title_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='news', + name='slug', + field=models.SlugField(blank=True, null=True), + ), + ] diff --git a/backend/sitemanagement/migrations/0005_news_created_at_alter_news_slug.py b/backend/sitemanagement/migrations/0005_news_created_at_alter_news_slug.py new file mode 100644 index 0000000..c1db74d --- /dev/null +++ b/backend/sitemanagement/migrations/0005_news_created_at_alter_news_slug.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.1 on 2025-05-15 16:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sitemanagement', '0004_news_slug'), + ] + + operations = [ + migrations.AddField( + model_name='news', + name='created_at', + field=models.DateTimeField(auto_now_add=True, null=True), + ), + migrations.AlterField( + model_name='news', + name='slug', + field=models.SlugField(blank=True, editable=False, null=True), + ), + ] diff --git a/backend/sitemanagement/models.py b/backend/sitemanagement/models.py index 572d185..96a1a0a 100644 --- a/backend/sitemanagement/models.py +++ b/backend/sitemanagement/models.py @@ -1,4 +1,8 @@ from django.db import models +from django.utils.text import slugify +from django.db.models.signals import pre_save +from django.dispatch import receiver +from transliterate import translit class FAQ (models.Model): title = models.CharField(max_length=250) @@ -12,3 +16,25 @@ class FAQ (models.Model): def __str__(self): return self.title + +class News(models.Model): + titleImage = models.ImageField(verbose_name="Главная картинка") + title = models.CharField(max_length=100, verbose_name="Заголовок") + content = models.TextField(max_length=1000, verbose_name="Контент статьи") + slug = models.SlugField(null=True, blank=True, editable=False) + created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True) + class Meta: + verbose_name = 'Новость' + verbose_name_plural = 'Новости' + ordering = ['id'] + + def __str__(self): + return self.title + +@receiver(pre_save, sender=News) +def generate_slug(sender, instance, **kwargs): + if not instance.slug: + # транслит с русского на латиницу + transliterated_title = translit(instance.title, 'ru', reversed=True) + # создаем слаг и заменяем пробелы на дефисы + instance.slug = slugify(transliterated_title) \ No newline at end of file diff --git a/frontend/components/FAQ.tsx b/frontend/components/FAQ.tsx index 7dca72a..78d4888 100644 --- a/frontend/components/FAQ.tsx +++ b/frontend/components/FAQ.tsx @@ -3,6 +3,10 @@ import Accordion from './ui/Accordion' import { FAQProps } from '@/app/types' const FAQ: React.FC = ({ faqs }) => { + if (!faqs || faqs.length === 0) { + return null + } + return (