Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bd9f787
add: i8n for landing page
Tim-Grube Mar 27, 2026
eecc184
add: i8n for login page
Tim-Grube Mar 27, 2026
f7adc9c
add: i8n for account settings
Tim-Grube Mar 27, 2026
379a78b
add: i8n for app settings
Tim-Grube Mar 27, 2026
04e4b74
add: i8n for faq settings
Tim-Grube Mar 27, 2026
4d94753
add: i8n for label settings
Tim-Grube Mar 27, 2026
3d9f0d8
add: i8n for user settings
Tim-Grube Mar 27, 2026
0c2dda0
add: i8n for ticket overview page
Tim-Grube Mar 28, 2026
a193dcf
add: i8n for ticket detail page
Tim-Grube Mar 28, 2026
e06cd93
add: i8n for components
Tim-Grube Mar 28, 2026
bb24462
fix: faulti i8n imports
Tim-Grube Mar 28, 2026
58de7a3
refactor: move more strings into the commons
Tim-Grube Mar 28, 2026
95c8b36
refactor: kummerform strings
Tim-Grube Mar 28, 2026
ca915ab
refactor: login page strings
Tim-Grube Mar 28, 2026
758421c
refactor: profile settings strings
Tim-Grube Mar 28, 2026
027379d
refactor: app settings strings
Tim-Grube Mar 28, 2026
6b954ef
refactor: kummerform strings 2
Tim-Grube Apr 7, 2026
096fa79
refactor: settings strings 2
Tim-Grube Apr 7, 2026
75251dc
refactor: faq settings strings
Tim-Grube Apr 7, 2026
9e30ce6
refactor: label settings strings
Tim-Grube Apr 7, 2026
a9727bb
refactor: user settings strings
Tim-Grube Apr 7, 2026
fc25aeb
refactor: ticket settings strings
Tim-Grube Apr 8, 2026
d678287
refactor: components strings
Tim-Grube Apr 8, 2026
47227d5
fix: faulty i8n paths in some components
Tim-Grube Apr 8, 2026
fbd8ade
implement: different locales usable
Tim-Grube Apr 8, 2026
0a329d2
implement: translate stuff
Tim-Grube Apr 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions frontend/app/(kummer-form)/form-about.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import React, { useEffect, useState } from "react";
import { Card, CardContent, CardTitle } from "@/components/ui/card";
import { getClient } from "@/lib/graph/client";
import { AboutSectionSettingsDocument } from "@/lib/graph/generated/graphql";
import {useTranslations} from "next-intl";

export default function AboutSection() {
const [text, setText] = useState<string>("");
const t = useTranslations('KummerkastenPage.AboutSection');

useEffect(() => {
const fetchAbout = async () => {
Expand All @@ -16,19 +18,19 @@ export default function AboutSection() {
setText(
textData.aboutSectionSettings?.find(
(s) => s?.key === "ABOUT_SECTION_TEXT"
)?.value ?? "Hello World!"
)?.value ?? t("noConfig")
);
} catch {
setText("Eine Beschreibung wurde nicht konfiguriert.");
setText(t("noConfig"));
}
};
void fetchAbout();
}, []);
}, [t]);

return (
<Card className="flex flex-col bg-kummerkasten-highlight-bg border-kummerkasten-highlight-bg w-full rounded-lg shadow-lg max-w-4xl mx-auto p-6 my-4">
<CardTitle className="text-3xl items-center text-center font-semibold text-foreground mb-2">
Was ist der Kummerkasten?
{t("title")}
</CardTitle>
<CardContent className="text-left" data-cy={'kummerform-about'}>
<p
Expand Down
14 changes: 9 additions & 5 deletions frontend/app/(kummer-form)/form-faq.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import {Accordion, AccordionContent, AccordionItem, AccordionTrigger,} from "@/c
import {LoaderCircle} from "lucide-react";
import {getClient} from "@/lib/graph/client";
import {AllQuestionAnswerPairDocument, QuestionAnswerPair} from "@/lib/graph/generated/graphql";
import {useTranslations} from "next-intl";
import { toast } from "sonner";


export default function FaqSection() {
const t = useTranslations("KummerkastenPage.FaqSection")
const tc = useTranslations("Commons")
const [faqs, setFaqs] = useState<QuestionAnswerPair[]>([]);
const [loading, setLoading] = useState<boolean>(true);

Expand All @@ -21,19 +25,19 @@ export default function FaqSection() {
.filter((faq) => !!faq);

setFaqs(filteredFaqs);
} catch (err) {
console.error("Failed to fetch FAQs:", err);
} catch {
toast.error(tc("toasts.fetchError"))
} finally {
setLoading(false);
}
};

void fetchFaqs();
}, []);
}, [t, tc]);

return (
<section className="w-full max-w-4xl mx-auto p-6 my-4 bg-kummerkasten-highlight-bg rounded-lg shadow-lg">
<h2 className="text-3xl font-semibold text-foreground-muted mb-6 text-center">Häufig gestellte Fragen</h2>
<h2 className="text-3xl font-semibold text-foreground-muted mb-6 text-center">{t("title")}</h2>
{loading && (
<div className="flex justify-center items-center py-8">
<LoaderCircle className="animate-spin h-8 w-8 text-foreground"/>
Expand All @@ -54,7 +58,7 @@ export default function FaqSection() {
</Accordion>
) : (
<div className="text-center text-foreground py-8" data-cy={'kummerform-faq-empty'}>
Keine FAQs verfügbar.
{t("noFaqs")}
</div>
)}
</section>
Expand Down
48 changes: 25 additions & 23 deletions frontend/app/(kummer-form)/form-ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,24 @@ import {Button} from "@/components/ui/button";
import {Textarea} from "@/components/ui/textarea";
import {Checkbox} from "@/components/ui/checkbox";
import {defaultLabel} from "@/lib/graph/defaultTypes";
import {useTranslations} from "next-intl";

const TITLE_MAX_LENGTH = 70
const TEXT_MAX_LENGTH = 3000

const formUiSchema = z.object({
labels: z.array(z.string())
.nonempty({error: "Bitte wähle mindestens ein Label aus."}),
title: z.string().nonempty({error: "Die Zusammenfassung darf nicht leer sein."})
.max(TITLE_MAX_LENGTH, "Die Zusammenfassung ist zu lang."),
text: z.string().nonempty({error: "Die Nachricht darf nicht leer sein."})
.max(TEXT_MAX_LENGTH, "Die Nachricht ist zu lang"),
});

export default function FormUi() {
const t = useTranslations("KummerkastenPage.FormUi")
const tc = useTranslations("Commons")

const formUiSchema = z.object({
labels: z.array(z.string()).nonempty({error: tc("fields.errors.empty")}),
title: z.string().nonempty({error: tc("fields.errors.empty")})
.max(TITLE_MAX_LENGTH, tc("fields.errors.long", {condition: `${TITLE_MAX_LENGTH} ${tc("words.characters")}`})),
text: z.string().nonempty({error: tc("fields.errors.empty")})
.max(TEXT_MAX_LENGTH, tc("fields.errors.long", {condition: `${TEXT_MAX_LENGTH} ${tc("words.characters")}`})),
});

const form = useForm<z.infer<typeof formUiSchema>>({
resolver: zodResolver(formUiSchema),
defaultValues: {
Expand Down Expand Up @@ -63,16 +67,15 @@ export default function FormUi() {

setFormLabels(filteredLabels);

} catch (err) {
console.error("Failed to fetch form labels:", err);
toast.error("Das Formular konnte nicht fertig geladen werden. Versuche es später erneut");
} catch {
toast.error(tc("toasts.fetchError"));
} finally {
setIsLabelsLoading(false);
}
};

void fetchPublicLabels();
}, [form]);
}, [form, tc]);

async function onValidSubmit(data: z.infer<typeof formUiSchema>) {
setLoading(true);
Expand All @@ -86,19 +89,18 @@ export default function FormUi() {

try {
await client.request<CreateTicketMutation>(CreateTicketDocument, {ticket: newTicket});
toast.success("Feedback wurde erfolgreich gesendet");
toast.success(t("toasts.sendSuccess"));
setHasTriedToSubmit(false);
form.reset();
} catch (error) {
toast.error("Beim Senden des Feedbacks ist ein Fehler aufgetreten.");
console.error(error);
} catch {
toast.error(t("toasts.generalError"));
}
setLoading(false);
}

return (
<div className="w-full max-w-4xl rounded-lg p-6 my-4 border">
<h2 className="text-3xl font-semibold text-foreground-muted mb-6 text-center">Deine anonyme Nachricht</h2>
<h2 className="text-3xl font-semibold text-foreground-muted mb-6 text-center">{t("title")}</h2>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onValidSubmit, () =>
Expand All @@ -112,7 +114,7 @@ export default function FormUi() {
render={() => (
<FormItem>
<FormLabel className={cn('data-[error=true]:text-destructive text-lg ')}>
Worum geht es in deinem Feedback?
{t("fields.labels.label")}
</FormLabel>
{isLabelsLoading &&
<div className="flex items-center justify-center">
Expand Down Expand Up @@ -173,7 +175,7 @@ export default function FormUi() {
render={({field}) => (
<FormItem>
<div className="flex justify-between items-center">
<FormLabel className="text-lg">Titel</FormLabel>
<FormLabel className="text-lg">{t("fields.title.label")}</FormLabel>
<span className={cn(
"text-sm text-muted-foreground",
field.value.length > TITLE_MAX_LENGTH && "text-destructive"
Expand All @@ -184,7 +186,7 @@ export default function FormUi() {
<FormControl>
<Input
className={cn("bg-background text-foreground")}
placeholder="Vorlesung ..."
placeholder={t("fields.title.placeholder")}
maxLength={TITLE_MAX_LENGTH}
data-cy={'kummerform-title-input'}
{...field}
Expand All @@ -200,7 +202,7 @@ export default function FormUi() {
render={({field}) => (
<FormItem>
<div className="flex justify-between items-center">
<FormLabel className="text-lg">Feedback</FormLabel>
<FormLabel className="text-lg">{t("fields.text.label")}</FormLabel>
<span className={cn(
"text-sm text-muted-foreground",
field.value.length > TEXT_MAX_LENGTH && "text-destructive"
Expand All @@ -210,7 +212,7 @@ export default function FormUi() {
</div>
<FormControl>
<Textarea
placeholder="Deine anonyme Nachricht"
placeholder={t("fields.text.placeholder")}
maxLength={TEXT_MAX_LENGTH}
className={cn("resize-none text-foreground flex min-h-[180px] bg-background text-sm",
"ring-offset-background focus-visible:outline-none focus-visible:ring-2",
Expand All @@ -233,7 +235,7 @@ export default function FormUi() {
) : (
<>
<Send/>
Absenden
{tc("buttons.send")}
</>
)}
</Button>
Expand Down
15 changes: 10 additions & 5 deletions frontend/app/(kummer-form)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,37 @@ import FAQSection from './form-faq';
import FormUi from './form-ui';
import Image from 'next/image';
import ThemeSwitch from "@/components/theme-switch";
import LanguageSwitch from "@/components/language-switch"
import {useTheme} from "next-themes";
import {useTranslations} from "next-intl";

export default function KummerkastenPage() {
const {resolvedTheme} = useTheme();
const t = useTranslations("KummerkastenPage.Root")

return (
<main className={'min-h-screen w-full relative'}>
<div
className="flex flex-col items-center py-10 px-4 sm:px-6 lg:px-8 space-y-8">
<ThemeSwitch
className={'absolute top-1 left-1 mt-2 ml-2 lg:mt-4 lg:ml-4'}
/>
<div className={' w-full flex flex-row items-center justify-start m-0'}>
<ThemeSwitch/>
<LanguageSwitch/>
</div>


<div className="flex items-center gap-5">
<Image
suppressHydrationWarning
src={resolvedTheme === "dark" ? "/logo_dark.svg" :"/logo_light.svg"}
alt="Kummerkasten Logo"
alt={t("logoAlt")}
width={512}
height={512}
className="w-16 h-16 sm:w-16 sm:h-16 lg:w-20 lg:h-20 xl:w-24 xl:h-24 mr-4"
/>
<h1
className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl font-extrabold tracking-tight text-foreground"
>
Kummerkasten
{t("title")}
</h1>
</div>

Expand Down
7 changes: 5 additions & 2 deletions frontend/app/(settings)/account/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import {ManagementPageHeader} from "@/components/management-page-header";
import {SettingsIcon} from "lucide-react";
import AccountDataForm from "@/app/(settings)/account/profile-data-form";
import PasswordDataForm from "@/app/(settings)/account/password-form";
import {useTranslations} from "next-intl";

export default function Page() {
const t = useTranslations("Settings.AccountPage.Root")

return (
<div className="w-full h-full">
<ManagementPageHeader
icon={<SettingsIcon/>}
title="Mein Account"
description="Bearbeite deine persönlichen Einstellungen"
title={t("title")}
description={t("description")}
/>
<AccountDataForm/>
<PasswordDataForm/>
Expand Down
Loading
Loading