From efc86ae9a98af0d309dcaeb56fb6dab6ecda0bf9 Mon Sep 17 00:00:00 2001 From: Jonas Ohrstrom Date: Fri, 28 Oct 2022 17:37:58 +0200 Subject: [PATCH] fix: add FAQ & content pages --- content/pages/donate.md | 12 -- core/faq/__init__.py | 0 core/faq/admin.py | 38 +++++++ core/faq/api/__init__.py | 0 core/faq/api/serializers.py | 32 ++++++ core/faq/api/urls.py | 11 ++ core/faq/api/views.py | 17 +++ core/faq/apps.py | 6 + core/faq/migrations/0001_initial.py | 103 ++++++++++++++++++ core/faq/migrations/__init__.py | 0 core/faq/models.py | 58 ++++++++++ core/faq/translation.py | 17 +++ core/settings/base.py | 1 + core/urls_api.py | 8 ++ package.json | 3 + src/App.vue | 3 + src/api/account.ts | 2 +- src/api/faq.ts | 17 +++ src/assets/pages/donate/twint-qr-code.png | Bin 0 -> 36824 bytes src/components/account/AuthPanel.vue | 76 ++++++++++--- src/components/account/EmailLoginForm.vue | 21 +++- src/components/account/EmailLoginVerify.vue | 4 + src/components/account/TokenInput.vue | 3 + .../account/context/ServiceInfoAside.vue | 30 +++++ src/components/account/legal/Availability.vue | 24 ++++ src/components/account/legal/Terms.vue | 25 +++++ src/components/faq/Topic.vue | 82 ++++++++++++++ src/components/geolocation/GeoblockNotice.vue | 83 ++++++++++++++ src/components/navigation/Navigation.vue | 8 +- src/components/navigation/SideMenu.vue | 10 +- src/components/ui/panel/OverlayPanel.vue | 16 +-- src/components/ui/panel/SidePanel.vue | 36 +++++- .../ui/section/ExpandableSection.vue | 83 ++++++++++++++ src/locales/de.yml | 15 +++ src/main.ts | 1 + src/router/index.ts | 16 +++ src/style/elements/form.scss | 9 +- src/style/elements/markdown.scss | 34 ++++++ src/typings/api/index.ts | 4 + src/typings/api/models/Category.ts | 19 ++++ .../api/models/PaginatedCategoryList.ts | 13 +++ src/typings/api/models/Topic.ts | 17 +++ src/typings/api/services/FaqService.ts | 32 ++++++ src/utils/account.ts | 4 +- src/views/faq/Faq.vue | 78 +++++++++++++ src/views/pages/Donate.vue | 98 +++++++++++++++++ src/views/pages/Page.vue | 66 +++++++++++ vite.config.ts | 2 + yarn.lock | 32 ++++++ 49 files changed, 1222 insertions(+), 47 deletions(-) delete mode 100644 content/pages/donate.md create mode 100644 core/faq/__init__.py create mode 100644 core/faq/admin.py create mode 100644 core/faq/api/__init__.py create mode 100644 core/faq/api/serializers.py create mode 100644 core/faq/api/urls.py create mode 100644 core/faq/api/views.py create mode 100644 core/faq/apps.py create mode 100644 core/faq/migrations/0001_initial.py create mode 100644 core/faq/migrations/__init__.py create mode 100644 core/faq/models.py create mode 100644 core/faq/translation.py create mode 100644 src/api/faq.ts create mode 100644 src/assets/pages/donate/twint-qr-code.png create mode 100644 src/components/account/context/ServiceInfoAside.vue create mode 100644 src/components/account/legal/Availability.vue create mode 100644 src/components/account/legal/Terms.vue create mode 100644 src/components/faq/Topic.vue create mode 100644 src/components/geolocation/GeoblockNotice.vue create mode 100644 src/components/ui/section/ExpandableSection.vue create mode 100644 src/style/elements/markdown.scss create mode 100644 src/typings/api/models/Category.ts create mode 100644 src/typings/api/models/PaginatedCategoryList.ts create mode 100644 src/typings/api/models/Topic.ts create mode 100644 src/typings/api/services/FaqService.ts create mode 100644 src/views/faq/Faq.vue create mode 100644 src/views/pages/Donate.vue create mode 100644 src/views/pages/Page.vue diff --git a/content/pages/donate.md b/content/pages/donate.md deleted file mode 100644 index 2be2436e..00000000 --- a/content/pages/donate.md +++ /dev/null @@ -1,12 +0,0 @@ -Title: Spende -Summary: Du kannst uns gerne mit einer Spende unterstützen. - -Du kannst uns gerne mit einer Spende unterstützen. - -*** - -IBAN: CH68 0900 0000 8537 9408 6 -PC: 85-379408-6 -BIC: POFICHBEXXX - -Wir danken für die Unterstützung. diff --git a/core/faq/__init__.py b/core/faq/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/core/faq/admin.py b/core/faq/admin.py new file mode 100644 index 00000000..e21dfd4b --- /dev/null +++ b/core/faq/admin.py @@ -0,0 +1,38 @@ +from django.contrib import admin + +from modeltranslation.admin import TranslationAdmin +from .models import Category, Topic + + +@admin.register(Category) +class CategoryAdmin(TranslationAdmin): + save_on_top = True + list_display = [ + "__str__", + "priority", + ] + search_fields = [ + "name", + ] + list_editable = [ + "priority", + ] + + +@admin.register(Topic) +class TopicAdmin(TranslationAdmin): + save_on_top = True + list_display = [ + "__str__", + "priority", + "category", + ] + search_fields = [ + "name", + ] + list_filter = [ + "category", + ] + list_editable = [ + "priority", + ] diff --git a/core/faq/api/__init__.py b/core/faq/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/core/faq/api/serializers.py b/core/faq/api/serializers.py new file mode 100644 index 00000000..5d034d99 --- /dev/null +++ b/core/faq/api/serializers.py @@ -0,0 +1,32 @@ +from rest_framework import serializers +from api_extra.serializers import CTUIDModelSerializer +from ..models import Category, Topic + + +class TopicSerializer( + CTUIDModelSerializer, + serializers.ModelSerializer, +): + class Meta(CTUIDModelSerializer.Meta): + model = Topic + fields = CTUIDModelSerializer.Meta.fields + [ + "question", + "answer", + ] + + +class CategorySerializer( + CTUIDModelSerializer, + serializers.ModelSerializer, +): + topics = TopicSerializer( + many=True, + read_only=True, + ) + + class Meta(CTUIDModelSerializer.Meta): + model = Category + fields = CTUIDModelSerializer.Meta.fields + [ + "name", + "topics", + ] diff --git a/core/faq/api/urls.py b/core/faq/api/urls.py new file mode 100644 index 00000000..283748d3 --- /dev/null +++ b/core/faq/api/urls.py @@ -0,0 +1,11 @@ +from django.urls import include, path +from rest_framework import routers +from . import views + +router = routers.DefaultRouter() +router.register("categories", views.CategoryViewSet) + +app_name = "faq" +urlpatterns = [ + path("", include(router.urls)), +] diff --git a/core/faq/api/views.py b/core/faq/api/views.py new file mode 100644 index 00000000..5f1ed797 --- /dev/null +++ b/core/faq/api/views.py @@ -0,0 +1,17 @@ +from rest_framework import mixins, viewsets +from . import serializers +from ..models import Category, Topic + + +class CategoryViewSet( + mixins.ListModelMixin, + viewsets.GenericViewSet, +): + queryset = Category.objects.all() + serializer_class = serializers.CategorySerializer + + def get_queryset(self): + # qs = self.queryset.prefetch_related( + # 'translations', + # ) + return self.queryset diff --git a/core/faq/apps.py b/core/faq/apps.py new file mode 100644 index 00000000..5ecb01a1 --- /dev/null +++ b/core/faq/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class FaqConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "faq" diff --git a/core/faq/migrations/0001_initial.py b/core/faq/migrations/0001_initial.py new file mode 100644 index 00000000..fd027e23 --- /dev/null +++ b/core/faq/migrations/0001_initial.py @@ -0,0 +1,103 @@ +# Generated by Django 3.2.15 on 2022-10-27 12:23 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Category", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created", models.DateTimeField(auto_now_add=True, db_index=True)), + ("updated", models.DateTimeField(auto_now=True, db_index=True)), + ( + "uuid", + models.UUIDField(db_index=True, default=uuid.uuid4, editable=False), + ), + ( + "uid", + models.CharField( + db_index=True, + editable=False, + max_length=8, + null=True, + unique=True, + ), + ), + ("name", models.CharField(max_length=64)), + ("name_en", models.CharField(max_length=64, null=True)), + ("name_de", models.CharField(max_length=64, null=True)), + ("name_fr", models.CharField(max_length=64, null=True)), + ("priority", models.PositiveSmallIntegerField(default=0)), + ], + options={ + "verbose_name": "Category", + "ordering": ["-priority", "name"], + }, + ), + migrations.CreateModel( + name="Topic", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created", models.DateTimeField(auto_now_add=True, db_index=True)), + ("updated", models.DateTimeField(auto_now=True, db_index=True)), + ( + "uuid", + models.UUIDField(db_index=True, default=uuid.uuid4, editable=False), + ), + ( + "uid", + models.CharField( + db_index=True, + editable=False, + max_length=8, + null=True, + unique=True, + ), + ), + ("question", models.TextField(max_length=256)), + ("question_en", models.TextField(max_length=256, null=True)), + ("question_de", models.TextField(max_length=256, null=True)), + ("question_fr", models.TextField(max_length=256, null=True)), + ("answer", models.TextField()), + ("answer_en", models.TextField(null=True)), + ("answer_de", models.TextField(null=True)), + ("answer_fr", models.TextField(null=True)), + ("priority", models.PositiveSmallIntegerField(default=0)), + ( + "category", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="faq.category" + ), + ), + ], + options={ + "verbose_name": "Topic", + "ordering": ["category", "-priority", "question"], + }, + ), + ] diff --git a/core/faq/migrations/__init__.py b/core/faq/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/core/faq/models.py b/core/faq/models.py new file mode 100644 index 00000000..a082a415 --- /dev/null +++ b/core/faq/models.py @@ -0,0 +1,58 @@ +from django.db import models +from base.models.mixins import TimestampedModelMixin, CTUIDModelMixin + + +class Category( + CTUIDModelMixin, + TimestampedModelMixin, + models.Model, +): + name = models.CharField( + max_length=64, + ) + priority = models.PositiveSmallIntegerField( + default=0, + ) + + class Meta: + app_label = "faq" + verbose_name = "Category" + verbose_name_plural = "Categories" + ordering = [ + "-priority", + "name", + ] + + def __str__(self): + return self.name + + +class Topic( + CTUIDModelMixin, + TimestampedModelMixin, + models.Model, +): + question = models.TextField( + max_length=256, + ) + answer = models.TextField() + priority = models.PositiveSmallIntegerField( + default=0, + ) + category = models.ForeignKey( + Category, + on_delete=models.CASCADE, + related_name="topics", + ) + + class Meta: + app_label = "faq" + verbose_name = "Topic" + ordering = [ + "category", + "-priority", + "question", + ] + + def __str__(self): + return self.question diff --git a/core/faq/translation.py b/core/faq/translation.py new file mode 100644 index 00000000..aa98f4b0 --- /dev/null +++ b/core/faq/translation.py @@ -0,0 +1,17 @@ +from modeltranslation.translator import register, TranslationOptions +from .models import Category, Topic + + +@register(Category) +class CategoryTranslationOptions(TranslationOptions): + fields = [ + "name", + ] + + +@register(Topic) +class TopicTranslationOptions(TranslationOptions): + fields = [ + "question", + "answer", + ] diff --git a/core/settings/base.py b/core/settings/base.py index c422a3a4..7b924aa7 100644 --- a/core/settings/base.py +++ b/core/settings/base.py @@ -59,6 +59,7 @@ "rating", "broadcast", "catalog", + "faq", "redirect", "electronic_mail", "stats", diff --git a/core/urls_api.py b/core/urls_api.py index b3ebe500..0ce33778 100644 --- a/core/urls_api.py +++ b/core/urls_api.py @@ -68,6 +68,10 @@ def api_root(request, format=None): "api:catalog:api-root", request=request, ), + "faq/": reverse( + "api:faq:api-root", + request=request, + ), } ) @@ -134,6 +138,10 @@ def api_root(request, format=None): "catalog/", include("catalog.api.urls", "catalog"), ), + path( + "faq/", + include("faq.api.urls", "faq"), + ), path( "redirect/", include("redirect.api.urls", "redirect"), diff --git a/package.json b/package.json index 71d8989f..63a63722 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@sentry/vue": "^6.18.2", "@stripe/stripe-js": "^1.24.0", "@vueuse/core": "8.3.1", + "@vueuse/router": "^9.4.0", "axios": "^0.26.1", "bowser": "^2.11.0", "color": "^4.2.3", @@ -37,6 +38,7 @@ "sass": "^1.49.9", "shaka-player": "4.1.0", "shifty": "^2.17.1", + "showdown": "^2.1.0", "vue": "^3.2.31", "vue-i18n": "^9.1.9", "vue-router": "^4.0.12", @@ -51,6 +53,7 @@ "@types/node-schedule": "^1.3.2", "@types/pulltorefreshjs": "^0.1.5", "@types/qs": "^6.9.7", + "@types/showdown": "^2.0.0", "@vitejs/plugin-vue": "^2.2.2", "@vue/eslint-config-prettier": "^7.0.0", "@vue/eslint-config-typescript": "^10.0.0", diff --git a/src/App.vue b/src/App.vue index 8b512658..289b8f83 100644 --- a/src/App.vue +++ b/src/App.vue @@ -8,6 +8,7 @@ import SideMenu from "@/components/navigation/SideMenu.vue"; import GlobalSearch from "@/components/navigation/GlobalSearch.vue"; import AuthPanel from "@/components/account/AuthPanel.vue"; import Subscribe from "@/components/subscription/Subscribe.vue"; +import GeoblockNotice from "@/components/geolocation/GeoblockNotice.vue"; import Player from "@/components/player/Player.vue"; import MobilePlayer from "@/components/player/mobile/Player.vue"; import Notifications from "@/components/notification/Notifications.vue"; @@ -29,6 +30,7 @@ export default defineComponent({ Notifications, AuthPanel, Subscribe, + GeoblockNotice, Player, ClaimVoucher, DebugPanel, @@ -62,6 +64,7 @@ export default defineComponent({ + diff --git a/src/api/account.ts b/src/api/account.ts index 70d58e44..e6137fa3 100644 --- a/src/api/account.ts +++ b/src/api/account.ts @@ -24,7 +24,7 @@ async function logout() { } async function checkLoginEmail(email: string) { - const url = `${ACCOUNT_ENDPOINT}send-email-login/?email=${email}`; + const url = `${ACCOUNT_ENDPOINT}send-email-login/?email=${encodeURIComponent(email)}`; const response = await APIClient.get(url); return response.data; } diff --git a/src/api/faq.ts b/src/api/faq.ts new file mode 100644 index 00000000..28cb3bde --- /dev/null +++ b/src/api/faq.ts @@ -0,0 +1,17 @@ +import { APIClient } from "@/api/client"; +import { useAPIBaseUrl } from "@/composables/api"; +const { APIBaseUrl } = useAPIBaseUrl(); + +const FAQ_ENDPOINT = `${APIBaseUrl.value}faq/categories/`; + +async function getFaqCategories(limit = 100, offset = 0) { + const url = FAQ_ENDPOINT; + const params = { + limit, + offset, + }; + const response = await APIClient.get(url, { params }); + return response.data; +} + +export { getFaqCategories }; diff --git a/src/assets/pages/donate/twint-qr-code.png b/src/assets/pages/donate/twint-qr-code.png new file mode 100644 index 0000000000000000000000000000000000000000..90e0c0f2ff51bdb22040ade543c81118a707ebe6 GIT binary patch literal 36824 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 diff --git a/src/components/account/legal/Availability.vue b/src/components/account/legal/Availability.vue new file mode 100644 index 00000000..c5233693 --- /dev/null +++ b/src/components/account/legal/Availability.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/components/account/legal/Terms.vue b/src/components/account/legal/Terms.vue new file mode 100644 index 00000000..50383f45 --- /dev/null +++ b/src/components/account/legal/Terms.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/src/components/faq/Topic.vue b/src/components/faq/Topic.vue new file mode 100644 index 00000000..24bf5110 --- /dev/null +++ b/src/components/faq/Topic.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/src/components/geolocation/GeoblockNotice.vue b/src/components/geolocation/GeoblockNotice.vue new file mode 100644 index 00000000..c3a7987c --- /dev/null +++ b/src/components/geolocation/GeoblockNotice.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/src/components/navigation/Navigation.vue b/src/components/navigation/Navigation.vue index eace0685..26e210ac 100644 --- a/src/components/navigation/Navigation.vue +++ b/src/components/navigation/Navigation.vue @@ -75,14 +75,14 @@ export default defineComponent({ grid-template-columns: 242px 1fr 146px 48px 48px; width: 100%; height: 78px; - padding: 0 1.5rem; + padding: 0 1.5rem 0 0; background: rgba(var(--c-page-bg), 0.6); border-bottom: 7px solid rgb(var(--c-page-fg)); transition: background 10ms; backdrop-filter: blur(24px); @include responsive.bp-medium { height: 66px; - grid-template-columns: 230px 1fr 40px 40px 40px; + grid-template-columns: 172px 1fr 40px 40px 40px; padding: 0 0.625rem; } .brand { @@ -90,6 +90,7 @@ export default defineComponent({ display: flex; align-items: center; justify-content: flex-start; + padding-left: 1.5rem; padding-right: 1rem; transition: color, background-color 200ms; .logo { @@ -103,6 +104,8 @@ export default defineComponent({ } @include responsive.bp-medium { line-height: 1.25rem; + padding-left: 0; + padding-right: 0; //margin-top: -10px; .logo { //width: 60px; @@ -112,6 +115,7 @@ export default defineComponent({ } > span { margin-top: -6px; + max-width: 100px; } } } diff --git a/src/components/navigation/SideMenu.vue b/src/components/navigation/SideMenu.vue index 197f1cb2..1e207cb2 100644 --- a/src/components/navigation/SideMenu.vue +++ b/src/components/navigation/SideMenu.vue @@ -43,6 +43,10 @@ export default defineComponent({ }; const pages = computed(() => { return [ + { + path: "/faq/", + title: t("menu.faq"), + }, { path: "/about/", title: t("menu.about"), @@ -214,9 +218,9 @@ export default defineComponent({ display: flex; min-height: 2rem; align-items: center; - border-top: 1px solid rgb(var(--c-gray-200)); - padding-top: 0.5rem; - padding-bottom: 1rem; + //border-top: 1px solid rgb(var(--c-gray-200)); + //padding-top: 0.5rem; + //padding-bottom: 1rem; .ui-mode-chooser { flex-grow: 1; } diff --git a/src/components/ui/panel/OverlayPanel.vue b/src/components/ui/panel/OverlayPanel.vue index acd1e57d..0173317f 100644 --- a/src/components/ui/panel/OverlayPanel.vue +++ b/src/components/ui/panel/OverlayPanel.vue @@ -1,5 +1,7 @@ + + + + diff --git a/src/locales/de.yml b/src/locales/de.yml index 947efb04..6f362dfa 100644 --- a/src/locales/de.yml +++ b/src/locales/de.yml @@ -23,6 +23,7 @@ menu: collection: Favoriten program: Programm reception: Empfang + faq: FAQ about: About contact: Kontakt donate: Spenden @@ -56,6 +57,15 @@ pullToRefresh: formActions: save: Speichern account: + legal: + terms: + term: By signing up you agree to the {0} and {1}. + tos: Terms of Service + pp: Privacy Policy + availability: + note: "Currently we can only provide access to our on-demand service for people living in Switzerland. + More about in the {0} section." + faq: FAQ personal: name: Name surname: Nachname @@ -67,3 +77,8 @@ account: female: she/her male: he/his other: they/them +geolocation: + availability: + note: Currently we can only provide access to our on-demand service for people living in Switzerland. + faqNote: More about in the {0} section. + faqLabel: FAQ diff --git a/src/main.ts b/src/main.ts index ee6090fb..dd5e6b16 100644 --- a/src/main.ts +++ b/src/main.ts @@ -49,6 +49,7 @@ const i18n = createI18n({ legacy: false, locale: settingsStore.locale, fallbackLocale: "de", + globalInjection: false, messages: { de, en, diff --git a/src/router/index.ts b/src/router/index.ts index c54d4e2d..bc312108 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -10,6 +10,7 @@ import Discover from "@/views/Discover.vue"; import Collection from "@/views/Collection.vue"; import Account from "@/views/Account.vue"; import Page from "@/views/cms/Page.vue"; +import Faq from "@/views/faq/Faq.vue"; import EditorList from "@/components/broadcast/editor/List.vue"; import MoodList from "@/components/catalog/mood/List.vue"; import MoodDetail from "@/views/catalog/MoodDetail.vue"; @@ -26,6 +27,8 @@ import AccountSettings from "@/components/account/settings/Settings.vue"; import DiscoverHeader from "@/layouts/DiscoverHeader.vue"; import Searchbar from "@/components/filter/Searchbar.vue"; // +import Donate from "@/views/pages/Donate.vue"; +// import ProtoBase from "@/views/proto/Proto.vue"; import ProtoIcons from "@/views/proto/Icons.vue"; import ProtoRating from "@/views/proto/Rating.vue"; @@ -406,6 +409,18 @@ const routes = [ }, ], }, + { + path: "/faq/", + name: "faq", + component: Faq, + }, + // non-cms pages + { + path: "/donate/", + name: "donate", + component: Donate, + }, + // prototypes { path: "/proto/", name: "proto", @@ -426,6 +441,7 @@ const routes = [ }, ], }, + // "cms" pages { path: "/:pathMatch(.*)*", name: "page", diff --git a/src/style/elements/form.scss b/src/style/elements/form.scss index a56fec99..247f45af 100644 --- a/src/style/elements/form.scss +++ b/src/style/elements/form.scss @@ -1,4 +1,5 @@ @use "@/style/base/typo"; +@use "@/style/abstracts/responsive"; @use "@/style/elements/button"; @mixin input { @@ -25,7 +26,7 @@ align-items: center; height: 3rem; color: inherit; - text-transform: uppercase; + //text-transform: uppercase; } .help { display: flex; @@ -37,6 +38,12 @@ cursor: pointer; } } + @include responsive.bp-medium { + label { + @include typo.small; + height: 2rem; + } + } } @mixin float-label { diff --git a/src/style/elements/markdown.scss b/src/style/elements/markdown.scss new file mode 100644 index 00000000..eece3a06 --- /dev/null +++ b/src/style/elements/markdown.scss @@ -0,0 +1,34 @@ +@charset "UTF-8"; + +@use "../abstracts/responsive"; + +@mixin default { + /* + rendered markdown - basic styling + */ + p, + ul, + ol, + pre { + &:not(:last-child) { + margin-bottom: 0.75rem; + } + } + ul, + ol { + list-style-position: outside; + margin-left: 1.25rem; + } + a { + text-decoration: underline; + } + pre { + color: white; + background: #333; + padding: 0.5rem; + user-select: text; + code { + font-size: 86%; + } + } +} \ No newline at end of file diff --git a/src/typings/api/index.ts b/src/typings/api/index.ts index 573d8574..0ce44923 100644 --- a/src/typings/api/index.ts +++ b/src/typings/api/index.ts @@ -10,6 +10,7 @@ export type { Address } from './models/Address'; export type { AddressCountries } from './models/AddressCountries'; export type { Artist } from './models/Artist'; export type { CatalogPlaylist } from './models/CatalogPlaylist'; +export type { Category } from './models/Category'; export type { ConnectedSocialBackend } from './models/ConnectedSocialBackend'; export { CountryEnum } from './models/CountryEnum'; export type { Editor } from './models/Editor'; @@ -28,6 +29,7 @@ export type { Mood } from './models/Mood'; export type { Page } from './models/Page'; export type { PaginatedArtistList } from './models/PaginatedArtistList'; export type { PaginatedCatalogPlaylistList } from './models/PaginatedCatalogPlaylistList'; +export type { PaginatedCategoryList } from './models/PaginatedCategoryList'; export type { PaginatedEditorList } from './models/PaginatedEditorList'; export type { PaginatedMediaList } from './models/PaginatedMediaList'; export type { PaginatedMoodList } from './models/PaginatedMoodList'; @@ -64,6 +66,7 @@ export type { TokenObtainSliding } from './models/TokenObtainSliding'; export type { TokenObtainSlidingRequest } from './models/TokenObtainSlidingRequest'; export type { TokenRefreshSliding } from './models/TokenRefreshSliding'; export type { TokenRefreshSlidingRequest } from './models/TokenRefreshSlidingRequest'; +export type { Topic } from './models/Topic'; export { TypeEnum } from './models/TypeEnum'; export type { User } from './models/User'; export type { Version } from './models/Version'; @@ -78,6 +81,7 @@ export { BroadcastService } from './services/BroadcastService'; export { CatalogService } from './services/CatalogService'; export { CmsService } from './services/CmsService'; export { DefaultService } from './services/DefaultService'; +export { FaqService } from './services/FaqService'; export { JwtService } from './services/JwtService'; export { PubSubBridgeService } from './services/PubSubBridgeService'; export { RatingService } from './services/RatingService'; diff --git a/src/typings/api/models/Category.ts b/src/typings/api/models/Category.ts new file mode 100644 index 00000000..423493af --- /dev/null +++ b/src/typings/api/models/Category.ts @@ -0,0 +1,19 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { Topic } from './Topic'; + +export type Category = { + /** + * Content type + */ + readonly ct?: string; + /** + * UID + */ + readonly uid?: string; + name: string; + readonly topics?: Array; +}; + diff --git a/src/typings/api/models/PaginatedCategoryList.ts b/src/typings/api/models/PaginatedCategoryList.ts new file mode 100644 index 00000000..42e83478 --- /dev/null +++ b/src/typings/api/models/PaginatedCategoryList.ts @@ -0,0 +1,13 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { Category } from './Category'; + +export type PaginatedCategoryList = { + count?: number; + next?: string | null; + previous?: string | null; + results?: Array; +}; + diff --git a/src/typings/api/models/Topic.ts b/src/typings/api/models/Topic.ts new file mode 100644 index 00000000..697f51c6 --- /dev/null +++ b/src/typings/api/models/Topic.ts @@ -0,0 +1,17 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type Topic = { + /** + * Content type + */ + readonly ct?: string; + /** + * UID + */ + readonly uid?: string; + question: string; + answer: string; +}; + diff --git a/src/typings/api/services/FaqService.ts b/src/typings/api/services/FaqService.ts new file mode 100644 index 00000000..7d1ae599 --- /dev/null +++ b/src/typings/api/services/FaqService.ts @@ -0,0 +1,32 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { PaginatedCategoryList } from '../models/PaginatedCategoryList'; + +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; + +export class FaqService { + + /** + * @param limit Number of results to return per page. + * @param offset The initial index from which to return the results. + * @returns PaginatedCategoryList + * @throws ApiError + */ + public static faqCategoriesList( + limit?: number, + offset?: number, + ): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/faq/categories/', + query: { + 'limit': limit, + 'offset': offset, + }, + }); + } + +} diff --git a/src/utils/account.ts b/src/utils/account.ts index 73b36c96..70cd5991 100644 --- a/src/utils/account.ts +++ b/src/utils/account.ts @@ -68,8 +68,8 @@ const requireSubscription = (fn: Function, message = "") => { const event = { message: subscription.value.isBlocked, }; - eventBus.emit("subscription:blocked", event); - alert(subscription.value.isBlocked); + eventBus.emit("geolocation:blocked", event); + // alert(subscription.value.isBlocked); return false; } if (!subscription.value.isActive) { diff --git a/src/views/faq/Faq.vue b/src/views/faq/Faq.vue new file mode 100644 index 00000000..923de535 --- /dev/null +++ b/src/views/faq/Faq.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/views/pages/Donate.vue b/src/views/pages/Donate.vue new file mode 100644 index 00000000..38a951f9 --- /dev/null +++ b/src/views/pages/Donate.vue @@ -0,0 +1,98 @@ + + + +de: + lead: Du kannst uns gerne mit einer Spende unterstützen. + bankTransfer: Überweisung + thankYou: Wir danken für die Unterstützung! +en: + lead: Support us + bankTransfer: Wire + thankYou: THX + + + + + diff --git a/src/views/pages/Page.vue b/src/views/pages/Page.vue new file mode 100644 index 00000000..e426ad77 --- /dev/null +++ b/src/views/pages/Page.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/vite.config.ts b/vite.config.ts index 66f1fe36..0363780c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -14,6 +14,8 @@ export default defineConfig({ plugins: [ vue(), vueI18n({ + runtimeOnly: true, + compositionOnly: true, include: resolve(__dirname, "src/locales/**"), }), ], diff --git a/yarn.lock b/yarn.lock index 8316ebb2..2da2d931 100644 --- a/yarn.lock +++ b/yarn.lock @@ -418,6 +418,11 @@ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== +"@types/showdown@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/showdown/-/showdown-2.0.0.tgz#3e800eca8573848cac4e5555f4377ba3a0e7b1f2" + integrity sha512-70xBJoLv+oXjB5PhtA8vo7erjLDp9/qqI63SRHm4REKrwuPOLs8HhXwlZJBJaB4kC18cCZ1UUZ6Fb/PLFW4TCA== + "@types/tough-cookie@*": version "4.0.1" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.1.tgz#8f80dd965ad81f3e1bc26d6f5c727e132721ff40" @@ -808,6 +813,14 @@ resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-8.3.1.tgz#acc0ff9ad686c68dfc7b4869639c43e71ae2682b" integrity sha512-1aZaFL44HzXXkfN6Q7KMDOXBFKTHDClHlOJBxtN8rTBXIIScoGOrJCpxWiQ4kuVg95MzG/pHrd3P4wd8poL9XQ== +"@vueuse/router@^9.4.0": + version "9.4.0" + resolved "https://registry.yarnpkg.com/@vueuse/router/-/router-9.4.0.tgz#df0e12d47bc1b08490b0d1384a05db170b1da840" + integrity sha512-nq7FJMDucngIxvvBvkdg8mgzqhyX9YnptOZozh5oVfbR3ZPVy/9U8VyDEt4CUsxs2Xwg4taA2PaO9xPsgkyruQ== + dependencies: + "@vueuse/shared" "9.4.0" + vue-demi "*" + "@vueuse/shared@8.3.1": version "8.3.1" resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-8.3.1.tgz#a941ef6a0eaf483ecb0e88a062163d506c22cc4b" @@ -815,6 +828,13 @@ dependencies: vue-demi "*" +"@vueuse/shared@9.4.0": + version "9.4.0" + resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.4.0.tgz#634022fe42b3d5ece1d81d749724966f5071c8c3" + integrity sha512-fTuem51KwMCnqUKkI8B57qAIMcFovtGgsCtAeqxIzH3i6nE9VYge+gVfneNHAAy7lj8twbkNfqQSygOPJTm4tQ== + dependencies: + vue-demi "*" + "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" @@ -1108,6 +1128,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@^9.0.0: + version "9.4.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" + integrity sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw== + commander@^9.3.0: version "9.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.3.0.tgz#f619114a5a2d2054e0d9ff1b31d5ccf89255e26b" @@ -2811,6 +2836,13 @@ shifty@^2.17.1: optionalDependencies: fsevents "^2.3.2" +showdown@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/showdown/-/showdown-2.1.0.tgz#1251f5ed8f773f0c0c7bfc8e6fd23581f9e545c5" + integrity sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ== + dependencies: + commander "^9.0.0" + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"