Merge branch 'release/1.25.3'
This commit is contained in:
6
app/[locale]/location/[id]/add/LocationAddPage.tsx
Normal file
6
app/[locale]/location/[id]/add/LocationAddPage.tsx
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { LocationEditForm } from '@/app/ui/LocationEditForm';
|
||||||
|
import { YearMonth } from '@/app/lib/db-types';
|
||||||
|
|
||||||
|
export default async function LocationAddPage({ yearMonth }: { yearMonth:YearMonth }) {
|
||||||
|
return (<LocationEditForm yearMonth={yearMonth} />);
|
||||||
|
}
|
||||||
11
app/[locale]/location/[id]/add/page.tsx
Normal file
11
app/[locale]/location/[id]/add/page.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { parseYearMonth } from '@/app/lib/format';
|
||||||
|
import LocationAddPage from './LocationAddPage';
|
||||||
|
import { Main } from '@/app/ui/Main';
|
||||||
|
|
||||||
|
export default async function Page({ params:{ id } }: { params: { id:string } }) {
|
||||||
|
return (
|
||||||
|
<Main>
|
||||||
|
<LocationAddPage yearMonth={ parseYearMonth(id) } />
|
||||||
|
</Main>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/[locale]/location/[id]/delete/LocationDeletePage.tsx
Normal file
14
app/[locale]/location/[id]/delete/LocationDeletePage.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { fetchLocationById } from '@/app/lib/actions/locationActions';
|
||||||
|
import { LocationDeleteForm } from '@/app/ui/LocationDeleteForm';
|
||||||
|
|
||||||
|
export const LocationDeletePage = async ({ locationId }: { locationId:string }) => {
|
||||||
|
|
||||||
|
const location = await fetchLocationById(locationId);
|
||||||
|
|
||||||
|
if (!location) {
|
||||||
|
return(notFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<LocationDeleteForm location={location} />);
|
||||||
|
}
|
||||||
6
app/[locale]/location/[id]/delete/not-found.tsx
Normal file
6
app/[locale]/location/[id]/delete/not-found.tsx
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { NotFoundPage } from '@/app/ui/NotFoundPage';
|
||||||
|
|
||||||
|
const BillingLocationNotFound = () =>
|
||||||
|
<NotFoundPage title="404 Billing Location Not Found" description="Could not find the requested Billing Location." />;
|
||||||
|
|
||||||
|
export default BillingLocationNotFound;
|
||||||
19
app/[locale]/location/[id]/delete/page.tsx
Normal file
19
app/[locale]/location/[id]/delete/page.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { fetchLocationById } from '@/app/lib/actions/locationActions';
|
||||||
|
import { LocationDeleteForm } from '@/app/ui/LocationDeleteForm';
|
||||||
|
import { Main } from '@/app/ui/Main';
|
||||||
|
|
||||||
|
export default async function Page({ params:{ id } }: { params: { id:string } }) {
|
||||||
|
|
||||||
|
const location = await fetchLocationById(id);
|
||||||
|
|
||||||
|
if (!location) {
|
||||||
|
return(notFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Main>
|
||||||
|
<LocationDeleteForm location={location} />
|
||||||
|
</Main>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
app/[locale]/location/[id]/edit/LocationEditPage.tsx
Normal file
16
app/[locale]/location/[id]/edit/LocationEditPage.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { LocationEditForm } from '@/app/ui/LocationEditForm';
|
||||||
|
import { fetchLocationById } from '@/app/lib/actions/locationActions';
|
||||||
|
|
||||||
|
export default async function LocationEditPage({ locationId }: { locationId:string }) {
|
||||||
|
|
||||||
|
const location = await fetchLocationById(locationId);
|
||||||
|
|
||||||
|
if (!location) {
|
||||||
|
return(notFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = <LocationEditForm location={location} />;
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
6
app/[locale]/location/[id]/edit/not-found.tsx
Normal file
6
app/[locale]/location/[id]/edit/not-found.tsx
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { NotFoundPage } from '@/app/ui/NotFoundPage';
|
||||||
|
|
||||||
|
const BillingLocationNotFound = () =>
|
||||||
|
<NotFoundPage title="404 Location Not Found" description="Could not find the requested Location." />;
|
||||||
|
|
||||||
|
export default BillingLocationNotFound;
|
||||||
15
app/[locale]/location/[id]/edit/page.tsx
Normal file
15
app/[locale]/location/[id]/edit/page.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { Suspense } from 'react';
|
||||||
|
import LocationEditPage from './LocationEditPage';
|
||||||
|
import { Main } from '@/app/ui/Main';
|
||||||
|
import { LocationEditFormSkeleton } from '@/app/ui/LocationEditForm';
|
||||||
|
|
||||||
|
export default async function Page({ params:{ id } }: { params: { id:string } }) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Main>
|
||||||
|
<Suspense fallback={<LocationEditFormSkeleton />}>
|
||||||
|
<LocationEditPage locationId={id} />
|
||||||
|
</Suspense>
|
||||||
|
</Main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ export type State = {
|
|||||||
*/
|
*/
|
||||||
const FormSchema = (t:IntlTemplateFn) => z.object({
|
const FormSchema = (t:IntlTemplateFn) => z.object({
|
||||||
_id: z.string(),
|
_id: z.string(),
|
||||||
billName: z.coerce.string().min(1, t("bill-name-required")),
|
billName: z.coerce.string().min(1, t("validation.bill-name-required")),
|
||||||
billNotes: z.string(),
|
billNotes: z.string(),
|
||||||
payedAmount: z.string().nullable().transform((val, ctx) => {
|
payedAmount: z.string().nullable().transform((val, ctx) => {
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ const FormSchema = (t:IntlTemplateFn) => z.object({
|
|||||||
if (isNaN(parsed)) {
|
if (isNaN(parsed)) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
message: t("not-a-number"),
|
message: t("validation.not-a-number"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// This is a special symbol you can use to
|
// This is a special symbol you can use to
|
||||||
@@ -52,7 +52,7 @@ const FormSchema = (t:IntlTemplateFn) => z.object({
|
|||||||
if (parsed < 0) {
|
if (parsed < 0) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
message: t("negative-number")
|
message: t("validation.negative-number")
|
||||||
});
|
});
|
||||||
|
|
||||||
// This is a special symbol you can use to
|
// This is a special symbol you can use to
|
||||||
@@ -115,7 +115,7 @@ export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationI
|
|||||||
|
|
||||||
const { id: userId } = user;
|
const { id: userId } = user;
|
||||||
|
|
||||||
const t = await getTranslations("bill-edit-form.validation");
|
const t = await getTranslations("bill-edit-form");
|
||||||
|
|
||||||
// FormSchema
|
// FormSchema
|
||||||
const validatedFields = FormSchema(t)
|
const validatedFields = FormSchema(t)
|
||||||
@@ -131,7 +131,7 @@ export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationI
|
|||||||
console.log("updateBill.validation-error");
|
console.log("updateBill.validation-error");
|
||||||
return({
|
return({
|
||||||
errors: validatedFields.error.flatten().fieldErrors,
|
errors: validatedFields.error.flatten().fieldErrors,
|
||||||
message: t("form-error-message"),
|
message: t("validation.form-error-message"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export type State = {
|
|||||||
*/
|
*/
|
||||||
const FormSchema = (t:IntlTemplateFn) => z.object({
|
const FormSchema = (t:IntlTemplateFn) => z.object({
|
||||||
_id: z.string(),
|
_id: z.string(),
|
||||||
locationName: z.coerce.string().min(1, t("location-name-required")),
|
locationName: z.coerce.string().min(1, t("validation.location-name-required")),
|
||||||
locationNotes: z.string(),
|
locationNotes: z.string(),
|
||||||
})
|
})
|
||||||
// dont include the _id field in the response
|
// dont include the _id field in the response
|
||||||
@@ -42,7 +42,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
|
|||||||
|
|
||||||
noStore();
|
noStore();
|
||||||
|
|
||||||
const t = await getTranslations("location-edit-form.validation");
|
const t = await getTranslations("location-edit-form");
|
||||||
|
|
||||||
const validatedFields = FormSchema(t).safeParse({
|
const validatedFields = FormSchema(t).safeParse({
|
||||||
locationName: formData.get('locationName'),
|
locationName: formData.get('locationName'),
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ export interface AddLocationButtonProps {
|
|||||||
|
|
||||||
export const AddLocationButton:React.FC<AddLocationButtonProps> = ({yearMonth}) => {
|
export const AddLocationButton:React.FC<AddLocationButtonProps> = ({yearMonth}) => {
|
||||||
|
|
||||||
const t = useTranslations("home-page.add-location-button");
|
const t = useTranslations("home-page");
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="card card-compact card-bordered bg-base-100 shadow-s my-1">
|
<div className="card card-compact card-bordered bg-base-100 shadow-s my-1">
|
||||||
<Link href={`/location/${ formatYearMonth(yearMonth) }/add`} className="card-body tooltip self-center" data-tip={t("tooltip")}>
|
<Link href={`/location/${ formatYearMonth(yearMonth) }/add`} className="card-body tooltip self-center" data-tip={t("add-location-button.tooltip")}>
|
||||||
<span className='flex self-center mr-[-3em]'>
|
<span className='flex self-center mr-[-3em]'>
|
||||||
<HomeIcon className="h-[1em] w-[1em] cursor-pointer text-4xl" />
|
<HomeIcon className="h-[1em] w-[1em] cursor-pointer text-4xl" />
|
||||||
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-xl text-green-500 ml-[-.6em] mt-[-.4em]" />
|
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-xl text-green-500 ml-[-.6em] mt-[-.4em]" />
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ export interface AddMonthButtonProps {
|
|||||||
|
|
||||||
export const AddMonthButton:React.FC<AddMonthButtonProps> = ({ yearMonth }) => {
|
export const AddMonthButton:React.FC<AddMonthButtonProps> = ({ yearMonth }) => {
|
||||||
|
|
||||||
const t = useTranslations("home-page.add-month-button");
|
const t = useTranslations("home-page");
|
||||||
const locale = useLocale();
|
const locale = useLocale();
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="card card-compact shadow-s mb-4">
|
<div className="card card-compact shadow-s mb-4">
|
||||||
<Link href={`/${locale}/year-month/${formatYearMonth(yearMonth)}/add`} className='grid self-center tooltip' data-tip={t("tooltip")}>
|
<Link href={`/${locale}/year-month/${formatYearMonth(yearMonth)}/add`} className='grid self-center tooltip' data-tip={t("add-month-button.tooltip")}>
|
||||||
<span className='flex self-center mr-[-3em]'>
|
<span className='flex self-center mr-[-3em]'>
|
||||||
<CalendarDaysIcon className="h-[1em] w-[1em] cursor-pointer text-4xl" />
|
<CalendarDaysIcon className="h-[1em] w-[1em] cursor-pointer text-4xl" />
|
||||||
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-xl text-green-500 ml-[-.4em] mt-[-.4em]" />
|
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-xl text-green-500 ml-[-.4em] mt-[-.4em]" />
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const BillDeleteForm:FC<BillDeleteFormProps> = ({ bill, location }) => {
|
|||||||
t.rich("text", {
|
t.rich("text", {
|
||||||
bill_name:bill.name,
|
bill_name:bill.name,
|
||||||
location_name:location.name,
|
location_name:location.name,
|
||||||
strong: (chunks:ReactNode) => `<strong>${chunks}</strong>`,
|
strong: (chunks:ReactNode) => <strong>${chunks}</strong>,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -38,11 +38,7 @@ export const LocationCard:FC<LocationCardProps> = ({location: { _id, name, yearM
|
|||||||
{
|
{
|
||||||
monthlyExpense > 0 ?
|
monthlyExpense > 0 ?
|
||||||
<p>
|
<p>
|
||||||
{
|
{ t("payed-total") } <strong>${monthlyExpense}</strong>
|
||||||
t.rich("payed-total", {
|
|
||||||
amount: formatCurrency(monthlyExpense),
|
|
||||||
strong: (chunks:ReactNode) => `<strong>${chunks}</strong>`
|
|
||||||
})}
|
|
||||||
</p>
|
</p>
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import { defaultLocale, localeNames, locales } from "../i18n";
|
|||||||
export const SelectLanguage: React.FC = () => {
|
export const SelectLanguage: React.FC = () => {
|
||||||
const currentPathname = usePathname();
|
const currentPathname = usePathname();
|
||||||
|
|
||||||
const locale = useLocale();
|
const currentLocale = useLocale();
|
||||||
const secondLocale = locales.find((l) => l !== locale) as string;
|
const secondLocale = locales.find((l) => l !== currentLocale) as string;
|
||||||
const secondLocalePathname = defaultLocale === locale ? `/${secondLocale}${currentPathname}` : currentPathname.replace(`/${locale}/`, `/${secondLocale}/`);
|
const secondLocalePathname = defaultLocale === currentLocale ? `/${secondLocale}${currentPathname}` : currentPathname.replace(`/${currentLocale}`, `/${secondLocale}`);
|
||||||
|
|
||||||
return (<Link className="btn btn-ghost text-xl self-end" href={secondLocalePathname}>{localeNames[secondLocale]}</Link>);
|
return (<Link className="btn btn-ghost text-xl self-end" href={secondLocalePathname}>{localeNames[secondLocale]}</Link>);
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ networks:
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
web-app:
|
web-app:
|
||||||
image: utility-bills-tracker:1.25.2
|
image: utility-bills-tracker:1.25.3
|
||||||
networks:
|
networks:
|
||||||
- traefik-network
|
- traefik-network
|
||||||
- mongo-network
|
- mongo-network
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
"location-card": {
|
"location-card": {
|
||||||
"edit-card-tooltip": "Edit realestate",
|
"edit-card-tooltip": "Edit realestate",
|
||||||
"add-bill-button-tooltip": "Add a new bill",
|
"add-bill-button-tooltip": "Add a new bill",
|
||||||
"payed-total": "Payed total: <strong>{amount}</strong>"
|
"payed-total": "Payed total:"
|
||||||
},
|
},
|
||||||
"month-card": {
|
"month-card": {
|
||||||
"payed-total-label": "Total monthly expenditure:"
|
"payed-total-label": "Total monthly expenditure:"
|
||||||
|
|||||||
Reference in New Issue
Block a user