Merge branch 'main' into B2B-88
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
# https://app.supabase.com/project/_/settings/api
|
||||
NEXT_PUBLIC_SUPABASE_URL=your-project-url
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
||||
NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
|
||||
|
||||
MEDIPOST_URL=your-medpost-url
|
||||
MEDIPOST_USER=your-medpost-user
|
||||
|
||||
@@ -9,20 +9,17 @@ import {
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
import { MedReportTitle } from '@/components/MedReportTitle';
|
||||
|
||||
function Home() {
|
||||
return (
|
||||
<div className={'mt-4 flex flex-col space-y-24 py-14'}>
|
||||
<div className={'container mx-auto'}>
|
||||
<Hero
|
||||
title={
|
||||
<>
|
||||
<span>Med Report</span>
|
||||
</>
|
||||
}
|
||||
title={<MedReportTitle />}
|
||||
subtitle={
|
||||
<span>
|
||||
Lihtne, mugav ja kiire ülevaade Sinu tervise seisundist
|
||||
<Trans i18nKey={'marketing:heroSubtitle'} />
|
||||
</span>
|
||||
}
|
||||
cta={<MainCallToActionButton />}
|
||||
@@ -56,8 +53,8 @@ function MainCallToActionButton() {
|
||||
</CtaButton>
|
||||
|
||||
<CtaButton variant={'link'}>
|
||||
<Link href={'/contact'}>
|
||||
<Trans i18nKey={'common:contactUs'} />
|
||||
<Link href={'/register-company'}>
|
||||
<Trans i18nKey={'account:createCompanyAccount'} />
|
||||
</Link>
|
||||
</CtaButton>
|
||||
</div>
|
||||
|
||||
11
app/(public)/layout.tsx
Normal file
11
app/(public)/layout.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
function SiteLayout(props: React.PropsWithChildren) {
|
||||
return (
|
||||
<div className={'flex min-h-[100vh] flex-col justify-center items-center'}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default withI18n(SiteLayout);
|
||||
90
app/(public)/register-company/page.tsx
Normal file
90
app/(public)/register-company/page.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
"use client";
|
||||
|
||||
import { MedReportTitle } from "@/components/MedReportTitle";
|
||||
import React from "react";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { companySchema } from "@/lib/validations/companySchema";
|
||||
import { CompanySubmitData } from "@/lib/types/company";
|
||||
import { submitCompanyRegistration } from "@/lib/services/register-company.service";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Label } from "@kit/ui/label";
|
||||
import { Input } from "@kit/ui/input";
|
||||
import { SubmitButton } from "@/components/ui/submit-button";
|
||||
import { FormItem } from "@kit/ui/form";
|
||||
import { Trans } from "@kit/ui/trans";
|
||||
|
||||
export default function RegisterCompany() {
|
||||
const router = useRouter();
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors, isValid, isSubmitting },
|
||||
} = useForm({
|
||||
resolver: yupResolver(companySchema),
|
||||
mode: "onChange",
|
||||
});
|
||||
|
||||
async function onSubmit(data: CompanySubmitData) {
|
||||
const formData = new FormData();
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
if (value !== undefined) formData.append(key, value);
|
||||
});
|
||||
|
||||
try {
|
||||
await submitCompanyRegistration(formData);
|
||||
router.push("/register-company/success");
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof Error) {
|
||||
alert("Server validation error: " + err.message);
|
||||
}
|
||||
alert("Server validation error");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-row border rounded-3xl border-border max-w-5xl overflow-hidden">
|
||||
<div className="flex flex-col text-center py-14 px-12 w-1/2">
|
||||
<MedReportTitle />
|
||||
<h1 className="pt-8">Ettevõtte andmed</h1>
|
||||
<p className="pt-2 text-muted-foreground text-sm">
|
||||
Pakkumise saamiseks palun sisesta ettevõtte andmed millega MedReport
|
||||
kasutada kavatsed.
|
||||
</p>
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
noValidate
|
||||
className="flex gap-7 flex-col text-left pt-8 px-6"
|
||||
>
|
||||
<FormItem>
|
||||
<Label>Ettevõtte nimi</Label>
|
||||
<Input {...register("companyName")} />
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Label>Kontaktisik</Label>
|
||||
<Input {...register("contactPerson")} />
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Label>E-mail</Label>
|
||||
<Input type="email" {...register("email")}></Input>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Label>Telefon</Label>
|
||||
<Input type="tel" {...register("phone")} />
|
||||
</FormItem>
|
||||
<SubmitButton
|
||||
disabled={!isValid || isSubmitting}
|
||||
pendingText="Saatmine..."
|
||||
type="submit"
|
||||
formAction={submitCompanyRegistration}
|
||||
className="mt-4 hover:bg-primary/90"
|
||||
>
|
||||
<Trans i18nKey={'account:requestCompanyAccount'} />
|
||||
</SubmitButton>
|
||||
</form>
|
||||
</div>
|
||||
<div className="w-1/2 min-w-[460px] bg-[url(/assets/med-report-logo-big.png)] bg-cover bg-center bg-no-repeat">
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
26
app/(public)/register-company/success/page.tsx
Normal file
26
app/(public)/register-company/success/page.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { MedReportTitle } from "@/components/MedReportTitle";
|
||||
import { Button } from "@/packages/ui/src/shadcn/button";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function CompanyRegistrationSuccess() {
|
||||
return (
|
||||
<div className="pt-2 px-16 pb-12 border rounded-3xl border-border">
|
||||
<MedReportTitle />
|
||||
<div className="flex flex-col items-center px-4">
|
||||
<Image
|
||||
src="/assets/success.png"
|
||||
alt="Success"
|
||||
className="pt-6 pb-8"
|
||||
width={326}
|
||||
height={195}
|
||||
/>
|
||||
<h1 className="pb-2">Päring edukalt saadetud!</h1>
|
||||
<p className=" text-muted-foreground text-sm">Saadame teile esimesel võimalusel vastuse</p>
|
||||
</div>
|
||||
<Button className="w-full mt-8">
|
||||
<Link href="/">Tagasi kodulehele</Link>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
22
app/(public)/sign-in/page.tsx
Normal file
22
app/(public)/sign-in/page.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Button } from '@kit/ui/button';
|
||||
import Link from "next/link";
|
||||
import React from "react";
|
||||
|
||||
export default async function SignIn() {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button variant="outline">
|
||||
<Link href="/">Smart-ID</Link>
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<Link href="/">Mobiil-ID</Link>
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<Link href="/">ID-Kaart</Link>
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<Link href="/register-company">Loo ettevõtte konto</Link>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
BIN
app/icon.ico
Normal file
BIN
app/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
10
components/MedReportTitle.tsx
Normal file
10
components/MedReportTitle.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import { MedReportSmallLogo } from "@/public/assets/MedReportSmallLogo";
|
||||
|
||||
export const MedReportTitle = () => (
|
||||
<div className="flex gap-2 justify-center">
|
||||
<MedReportSmallLogo />
|
||||
<span className="text-foreground text-lg font-semibold tracking-tighter">
|
||||
MedReport
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
67
components/header-auth.tsx
Normal file
67
components/header-auth.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { signOutAction } from "@/lib/actions/sign-out";
|
||||
import { hasEnvVars } from "@/utils/supabase/check-env-vars";
|
||||
import Link from "next/link";
|
||||
import { Badge } from "./ui/badge";
|
||||
import { Button } from "./ui/button";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
export default async function AuthButton() {
|
||||
const supabase = await createClient();
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
||||
if (!hasEnvVars) {
|
||||
return (
|
||||
<>
|
||||
<div className="flex gap-4 items-center">
|
||||
<div>
|
||||
<Badge
|
||||
variant={"default"}
|
||||
className="font-normal pointer-events-none"
|
||||
>
|
||||
Please update .env.local file with anon key and url
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
asChild
|
||||
size="sm"
|
||||
variant={"outline"}
|
||||
disabled
|
||||
className="opacity-75 cursor-none pointer-events-none"
|
||||
>
|
||||
<Link href="/sign-in">Sign in</Link>
|
||||
</Button>
|
||||
<Button
|
||||
asChild
|
||||
size="sm"
|
||||
variant={"default"}
|
||||
disabled
|
||||
className="opacity-75 cursor-none pointer-events-none"
|
||||
>
|
||||
<Link href="example/sign-up">Sign up</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return user ? (
|
||||
<div className="flex items-center gap-4">
|
||||
Hey, {user.email}!
|
||||
<form action={signOutAction}>
|
||||
<Button type="submit" variant={"outline"}>
|
||||
Sign out
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex gap-2">
|
||||
<Button asChild size="sm" variant={"outline"}>
|
||||
<Link href="/sign-in">Sign in</Link>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
23
components/ui/submit-button.tsx
Normal file
23
components/ui/submit-button.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@kit/ui/button";
|
||||
import { type ComponentProps } from "react";
|
||||
import { useFormStatus } from "react-dom";
|
||||
|
||||
type Props = ComponentProps<typeof Button> & {
|
||||
pendingText?: string;
|
||||
};
|
||||
|
||||
export function SubmitButton({
|
||||
children,
|
||||
pendingText = "Submitting...",
|
||||
...props
|
||||
}: Props) {
|
||||
const { pending } = useFormStatus();
|
||||
|
||||
return (
|
||||
<Button type="submit" aria-disabled={pending} {...props}>
|
||||
{pending ? pendingText : children}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
BIN
fonts/InterDisplay-Medium.woff2
Normal file
BIN
fonts/InterDisplay-Medium.woff2
Normal file
Binary file not shown.
BIN
fonts/InterDisplay-Regular.woff2
Normal file
BIN
fonts/InterDisplay-Regular.woff2
Normal file
Binary file not shown.
10
lib/actions/sign-out.tsx
Normal file
10
lib/actions/sign-out.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
"use server";
|
||||
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export const signOutAction = async () => {
|
||||
const supabase = await createClient();
|
||||
await supabase.auth.signOut();
|
||||
return redirect("/sign-in");
|
||||
};
|
||||
27
lib/fonts.ts
27
lib/fonts.ts
@@ -1,4 +1,5 @@
|
||||
import { Inter as SansFont } from 'next/font/google';
|
||||
import { Geist as HeadingFont } from 'next/font/google';
|
||||
import SansFont from 'next/font/local';
|
||||
|
||||
import { cn } from '@kit/ui/utils';
|
||||
|
||||
@@ -8,18 +9,32 @@ import { cn } from '@kit/ui/utils';
|
||||
* By default, it uses the Inter font from Google Fonts.
|
||||
*/
|
||||
const sans = SansFont({
|
||||
subsets: ['latin'],
|
||||
variable: '--font-sans',
|
||||
fallback: ['system-ui', 'Helvetica Neue', 'Helvetica', 'Arial'],
|
||||
preload: true,
|
||||
weight: ['300', '400', '500', '600', '700'],
|
||||
src: [
|
||||
{
|
||||
path: '../fonts/InterDisplay-Regular.woff2',
|
||||
weight: '400',
|
||||
style: 'normal',
|
||||
},
|
||||
{
|
||||
path: '../fonts/InterDisplay-Medium.woff2',
|
||||
weight: '500',
|
||||
style: 'medium',
|
||||
},
|
||||
],
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* @heading
|
||||
* @description Define here the heading font.
|
||||
*/
|
||||
const heading = sans;
|
||||
const heading = HeadingFont({
|
||||
variable: '--font-heading',
|
||||
fallback: ['system-ui', 'Helvetica Neue', 'Helvetica', 'Arial'],
|
||||
preload: true,
|
||||
weight: ['300', '400', '500', '600', '700'],
|
||||
});
|
||||
|
||||
// we export these fonts into the root layout
|
||||
export { sans, heading };
|
||||
|
||||
@@ -12,7 +12,7 @@ const defaultLanguage = process.env.NEXT_PUBLIC_DEFAULT_LOCALE ?? 'en';
|
||||
* By default, only the default language is supported.
|
||||
* Add more languages here if needed.
|
||||
*/
|
||||
export const languages: string[] = [defaultLanguage];
|
||||
export const languages: string[] = [defaultLanguage, 'en', 'ru'];
|
||||
|
||||
/**
|
||||
* The name of the cookie that stores the selected language.
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import {
|
||||
GetMessageListResponse,
|
||||
MedipostAction,
|
||||
MedipostPublicMessageResponse,
|
||||
Message,
|
||||
UuringuGrupp,
|
||||
} from "@/lib/types/medipost";
|
||||
import { Tables } from "@/supabase/database.types";
|
||||
import { createClient, SupabaseClient } from "@supabase/supabase-js";
|
||||
import axios from "axios";
|
||||
import { xml2json } from "xml-js";
|
||||
import { XMLParser } from "fast-xml-parser";
|
||||
import { SyncStatus } from "@/lib/types/audit";
|
||||
import { toArray } from "@/lib/utils";
|
||||
|
||||
const BASE_URL = process.env.MEDIPOST_URL!;
|
||||
const USER = process.env.MEDIPOST_USER!;
|
||||
@@ -15,9 +21,10 @@ export async function getMessages() {
|
||||
const publicMessage = await getLatestPublicMessageListItem();
|
||||
|
||||
if (!publicMessage) {
|
||||
return [];
|
||||
return null;
|
||||
}
|
||||
|
||||
//Teenused tuleb mappida kokku MedReport teenustega. <UuringId> alusel
|
||||
return getPublicMessage(publicMessage.messageId);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@@ -55,18 +62,13 @@ export async function getPublicMessage(messageId: string) {
|
||||
Accept: "application/xml",
|
||||
},
|
||||
});
|
||||
const parser = new XMLParser({ ignoreAttributes: false });
|
||||
const parsed: MedipostPublicMessageResponse = parser.parse(data);
|
||||
|
||||
if (data.code && data.code !== 0) {
|
||||
if (parsed.ANSWER?.CODE && parsed.ANSWER?.CODE !== 0) {
|
||||
throw new Error(`Failed to get public message (id: ${messageId})`);
|
||||
}
|
||||
|
||||
const parsed = JSON.parse(
|
||||
xml2json(data, {
|
||||
compact: true,
|
||||
spaces: 2,
|
||||
})
|
||||
);
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
@@ -124,14 +126,8 @@ export async function getPrivateMessage(messageId: string) {
|
||||
throw new Error(`Failed to get private message (id: ${messageId})`);
|
||||
}
|
||||
|
||||
const parsed = JSON.parse(
|
||||
xml2json(data, {
|
||||
compact: true,
|
||||
spaces: 2,
|
||||
})
|
||||
);
|
||||
|
||||
return parsed;
|
||||
const parser = new XMLParser({ ignoreAttributes: false });
|
||||
return parser.parse(data);
|
||||
}
|
||||
|
||||
export async function deletePrivateMessage(messageId: string) {
|
||||
@@ -170,6 +166,187 @@ export async function readPrivateMessageResponse() {
|
||||
}
|
||||
}
|
||||
|
||||
async function saveAnalysisGroup(
|
||||
analysisGroup: UuringuGrupp,
|
||||
supabase: SupabaseClient
|
||||
) {
|
||||
const { data: insertedAnalysisGroup, error } = await supabase
|
||||
.from("analysis_groups")
|
||||
.upsert(
|
||||
{
|
||||
original_id: analysisGroup.UuringuGruppId,
|
||||
name: analysisGroup.UuringuGruppNimi,
|
||||
order: analysisGroup.UuringuGruppJarjekord,
|
||||
},
|
||||
{ onConflict: "original_id", ignoreDuplicates: false }
|
||||
)
|
||||
.select("id");
|
||||
|
||||
if (error || !insertedAnalysisGroup[0]?.id) {
|
||||
throw new Error(
|
||||
`Failed to insert analysis group (id: ${analysisGroup.UuringuGruppId}), error: ${error?.message}`
|
||||
);
|
||||
}
|
||||
const analysisGroupId = insertedAnalysisGroup[0].id;
|
||||
|
||||
const analysisGroupCodes = toArray(analysisGroup.Kood);
|
||||
const codes: Partial<Tables<"codes">>[] = analysisGroupCodes.map((kood) => ({
|
||||
hk_code: kood.HkKood,
|
||||
hk_code_multiplier: kood.HkKoodiKordaja,
|
||||
coefficient: kood.Koefitsient,
|
||||
price: kood.Hind,
|
||||
analysis_group_id: analysisGroupId,
|
||||
}));
|
||||
|
||||
const analysisGroupItems = toArray(analysisGroup.Uuring);
|
||||
|
||||
for (const item of analysisGroupItems) {
|
||||
const analysisElement = item.UuringuElement;
|
||||
|
||||
const { data: insertedAnalysisElement, error } = await supabase
|
||||
.from("analysis_elements")
|
||||
.upsert(
|
||||
{
|
||||
analysis_id_oid: analysisElement.UuringIdOID,
|
||||
analysis_id_original: analysisElement.UuringId,
|
||||
tehik_short_loinc: analysisElement.TLyhend,
|
||||
tehik_loinc_name: analysisElement.KNimetus,
|
||||
analysis_name_lab: analysisElement.UuringNimi,
|
||||
order: analysisElement.Jarjekord,
|
||||
parent_analysis_group_id: analysisGroupId,
|
||||
material_groups: toArray(item.MaterjalideGrupp),
|
||||
},
|
||||
{ onConflict: "analysis_id_original", ignoreDuplicates: false }
|
||||
)
|
||||
.select('id');
|
||||
|
||||
if (error || !insertedAnalysisElement[0]?.id) {
|
||||
throw new Error(
|
||||
`Failed to insert analysis element (id: ${analysisElement.UuringId}), error: ${error?.message}`
|
||||
);
|
||||
}
|
||||
|
||||
const insertedAnalysisElementId = insertedAnalysisElement[0].id;
|
||||
|
||||
if (analysisElement.Kood) {
|
||||
const analysisElementCodes = toArray(analysisElement.Kood);
|
||||
codes.push(
|
||||
...analysisElementCodes.map((kood) => ({
|
||||
hk_code: kood.HkKood,
|
||||
hk_code_multiplier: kood.HkKoodiKordaja,
|
||||
coefficient: kood.Koefitsient,
|
||||
price: kood.Hind,
|
||||
analysis_element_id: insertedAnalysisElementId,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
const analyses = analysisElement.UuringuElement;
|
||||
if (analyses?.length) {
|
||||
for (const analysis of analyses) {
|
||||
const { data: insertedAnalysis, error } = await supabase
|
||||
.from("analyses")
|
||||
.upsert(
|
||||
{
|
||||
analysis_id_oid: analysis.UuringIdOID,
|
||||
analysis_id_original: analysis.UuringId,
|
||||
tehik_short_loinc: analysis.TLyhend,
|
||||
tehik_loinc_name: analysis.KNimetus,
|
||||
analysis_name_lab: analysis.UuringNimi,
|
||||
order: analysis.Jarjekord,
|
||||
parent_analysis_element_id: insertedAnalysisElementId,
|
||||
},
|
||||
{ onConflict: "analysis_id_original", ignoreDuplicates: false }
|
||||
)
|
||||
.select('id');
|
||||
|
||||
if (error || !insertedAnalysis[0]?.id) {
|
||||
throw new Error(
|
||||
`Failed to insert analysis (id: ${analysis.UuringId}) error: ${error?.message}`
|
||||
);
|
||||
}
|
||||
|
||||
const insertedAnalysisId = insertedAnalysis[0].id;
|
||||
if (analysisElement.Kood) {
|
||||
const analysisCodes = toArray(analysis.Kood);
|
||||
|
||||
codes.push(
|
||||
...analysisCodes.map((kood) => ({
|
||||
hk_code: kood.HkKood,
|
||||
hk_code_multiplier: kood.HkKoodiKordaja,
|
||||
coefficient: kood.Koefitsient,
|
||||
price: kood.Hind,
|
||||
analysis_id: insertedAnalysisId,
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { error: codesError } = await supabase
|
||||
.from("codes")
|
||||
.upsert(codes, { ignoreDuplicates: false });
|
||||
|
||||
if (codesError?.code) {
|
||||
throw new Error(
|
||||
`Failed to insert codes (analysis group id: ${analysisGroup.UuringuGruppId})`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function syncPublicMessage(
|
||||
message?: MedipostPublicMessageResponse | null
|
||||
) {
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY!,
|
||||
{
|
||||
auth: {
|
||||
persistSession: false,
|
||||
autoRefreshToken: false,
|
||||
detectSessionInUrl: false,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
const providers = toArray(message?.Saadetis?.Teenused.Teostaja);
|
||||
const analysisGroups = providers.flatMap((provider) =>
|
||||
toArray(provider.UuringuGrupp)
|
||||
);
|
||||
if (!message || !analysisGroups.length) {
|
||||
return supabase.schema("audit").from("sync_entries").insert({
|
||||
operation: "ANALYSES_SYNC",
|
||||
comment: "No data received",
|
||||
status: SyncStatus.Fail,
|
||||
changed_by_role: "service_role",
|
||||
});
|
||||
}
|
||||
|
||||
for (const analysisGroup of analysisGroups) {
|
||||
await saveAnalysisGroup(analysisGroup, supabase);
|
||||
}
|
||||
|
||||
await supabase.schema("audit").from("sync_entries").insert({
|
||||
operation: "ANALYSES_SYNC",
|
||||
status: SyncStatus.Success,
|
||||
changed_by_role: "service_role",
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
await supabase
|
||||
.schema("audit")
|
||||
.from("sync_entries")
|
||||
.insert({
|
||||
operation: "ANALYSES_SYNC",
|
||||
status: SyncStatus.Fail,
|
||||
comment: JSON.stringify(e),
|
||||
changed_by_role: "service_role",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getLatestMessage(messages?: Message[]) {
|
||||
if (!messages?.length) {
|
||||
return null;
|
||||
|
||||
31
lib/services/register-company.service.ts
Normal file
31
lib/services/register-company.service.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
"use server";
|
||||
|
||||
import * as yup from "yup";
|
||||
import { companySchema } from "@/lib/validations/companySchema";
|
||||
|
||||
export async function submitCompanyRegistration(formData: FormData) {
|
||||
const data = {
|
||||
companyName: formData.get("companyName")?.toString() || "",
|
||||
contactPerson: formData.get("contactPerson")?.toString() || "",
|
||||
email: formData.get("email")?.toString() || "",
|
||||
phone: formData.get("phone")?.toString() || "",
|
||||
};
|
||||
|
||||
try {
|
||||
await companySchema.validate(data, { abortEarly: false });
|
||||
|
||||
console.log("Valid data:", data);
|
||||
} catch (validationError) {
|
||||
if (validationError instanceof yup.ValidationError) {
|
||||
const errors = validationError.inner.map((err) => ({
|
||||
path: err.path,
|
||||
message: err.message,
|
||||
}));
|
||||
throw new Error(
|
||||
"Validation failed: " +
|
||||
errors.map((e) => `${e.path}: ${e.message}`).join(", ")
|
||||
);
|
||||
}
|
||||
throw validationError;
|
||||
}
|
||||
}
|
||||
4
lib/types/audit.ts
Normal file
4
lib/types/audit.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export enum SyncStatus {
|
||||
Success = "SUCCESS",
|
||||
Fail = "FAIL",
|
||||
}
|
||||
6
lib/types/company.ts
Normal file
6
lib/types/company.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface CompanySubmitData {
|
||||
companyName: string;
|
||||
contactPerson: string;
|
||||
email: string;
|
||||
phone?: string;
|
||||
}
|
||||
@@ -20,3 +20,122 @@ export enum MedipostAction {
|
||||
GetPrivateMessage = "GetPrivateMessage",
|
||||
DeletePrivateMessage = "DeletePrivateMessage",
|
||||
}
|
||||
|
||||
export type VoimalikVaartus = {
|
||||
VaartusId: string;
|
||||
Vaartus: "jah" | "ei";
|
||||
VaartusJarjekord: number;
|
||||
};
|
||||
|
||||
export type Sisendparameeter = {
|
||||
"@_VastuseTyyp"?: "ARV" | "VABATEKST" | "KODEERITUD" | "AJAHETK";
|
||||
"@_VastuseKoodistikuOID"?: string;
|
||||
"@_VastuseKoodistikuNimi"?: string;
|
||||
"@_URL"?: string;
|
||||
|
||||
UuringIdOID: string;
|
||||
UuringId: string;
|
||||
TLyhend: string;
|
||||
KNimetus: string;
|
||||
UuringNimi: string;
|
||||
Jarjekord: number;
|
||||
|
||||
VoimalikVaartus: VoimalikVaartus[];
|
||||
};
|
||||
|
||||
export type Kood = {
|
||||
HkKood: string;
|
||||
HkKoodiKordaja: number;
|
||||
Koefitsient: number; // float
|
||||
Hind: number; // float
|
||||
};
|
||||
|
||||
export type UuringuAlamElement = {
|
||||
UuringIdOID: string;
|
||||
UuringId: string;
|
||||
TLyhend: string;
|
||||
KNimetus: string;
|
||||
UuringNimi: string;
|
||||
Jarjekord: string;
|
||||
Kood?: Kood[];
|
||||
};
|
||||
|
||||
export type UuringuElement = {
|
||||
UuringIdOID: string;
|
||||
UuringId: string;
|
||||
TLyhend: string;
|
||||
KNimetus: string;
|
||||
UuringNimi: string;
|
||||
Jarjekord: string;
|
||||
Kood?: Kood[];
|
||||
UuringuElement?: UuringuAlamElement[];
|
||||
};
|
||||
|
||||
export type Uuring = {
|
||||
tellitav: "JAH" | "EI";
|
||||
UuringuElement: UuringuElement; //1..1
|
||||
MaterjalideGrupp?: MaterjalideGrupp[]; //0..n
|
||||
};
|
||||
|
||||
export type UuringuGrupp = {
|
||||
UuringuGruppId: string;
|
||||
UuringuGruppNimi: string;
|
||||
UuringuGruppJarjekord: number;
|
||||
Uuring: Uuring | Uuring[]; //1..n
|
||||
Kood?: Kood | Kood[]; //0..n
|
||||
};
|
||||
|
||||
export type Konteiner = {
|
||||
ProovinouKoodOID: string;
|
||||
ProovinouKood: string;
|
||||
KonteineriNimi: string;
|
||||
KonteineriKirjeldus: string;
|
||||
};
|
||||
|
||||
export type Materjal = {
|
||||
MaterjaliTyypOID: string;
|
||||
MaterjaliTyyp: string;
|
||||
MaterjaliNimi: string;
|
||||
KonteineriOmadus: string;
|
||||
MaterjaliPaige: { Kohustuslik: "JAH" | "EI" }; //0..1
|
||||
Konteiner?: Konteiner[]; //0..n
|
||||
};
|
||||
|
||||
export type MaterjalideGrupp = {
|
||||
vaikimisi: "JAH" | "EI";
|
||||
Materjal: Materjal; //1..n
|
||||
};
|
||||
|
||||
export type Teostaja = {
|
||||
UuringuGrupp?: UuringuGrupp | UuringuGrupp[]; //0...n
|
||||
Asutus: {
|
||||
AsutuseId: string;
|
||||
AsutuseNimi: string;
|
||||
AsutuseKood: string;
|
||||
AllyksuseNimi: string;
|
||||
Telefon: string;
|
||||
Aadress: string;
|
||||
};
|
||||
Sisendparameeter?: Sisendparameeter | Sisendparameeter[]; //0...n
|
||||
};
|
||||
|
||||
export type MedipostPublicMessageResponse = {
|
||||
"?xml": {
|
||||
"@_version": string;
|
||||
"@_encoding": "UTF-8";
|
||||
"@_standalone"?: "yes" | "no";
|
||||
};
|
||||
ANSWER?: { CODE: number };
|
||||
Saadetis?: {
|
||||
Pais: {
|
||||
Pakett: { "#text": "SL" | "OL" | "AL" | "ME" }; // SL - Teenused, OL - Tellimus (meie poolt saadetav saatekiri), AL - Vastus (saatekirja vastus), ME - Teade
|
||||
Saatja: string;
|
||||
Saaja: string;
|
||||
Aeg: string;
|
||||
SaadetisId: string;
|
||||
};
|
||||
Teenused: {
|
||||
Teostaja: Teostaja | Teostaja[]; //1..n
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4,3 +4,8 @@ import { twMerge } from "tailwind-merge";
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
export function toArray<T>(input?: T | T[] | null): T[] {
|
||||
if (!input) return [];
|
||||
return Array.isArray(input) ? input : [input];
|
||||
}
|
||||
|
||||
8
lib/validations/companySchema.ts
Normal file
8
lib/validations/companySchema.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import * as yup from "yup";
|
||||
|
||||
export const companySchema = yup.object({
|
||||
companyName: yup.string().required("Company name is required"),
|
||||
contactPerson: yup.string().required("Contact person is required"),
|
||||
email: yup.string().email("Invalid email").required("Email is required"),
|
||||
phone: yup.string().optional(),
|
||||
});
|
||||
@@ -61,6 +61,7 @@
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"axios": "^1.9.0",
|
||||
"clsx": "^2.1.1",
|
||||
"fast-xml-parser": "^5.2.3",
|
||||
"date-fns": "^4.1.0",
|
||||
"lucide-react": "^0.510.0",
|
||||
"next": "15.3.2",
|
||||
@@ -73,10 +74,10 @@
|
||||
"recharts": "2.15.3",
|
||||
"sonner": "^2.0.3",
|
||||
"tailwind-merge": "^3.3.0",
|
||||
"xml-js": "^1.6.11",
|
||||
"zod": "^3.24.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hookform/resolvers": "^5.0.1",
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
@@ -85,6 +86,7 @@
|
||||
"@types/node": "^22.15.18",
|
||||
"@types/react": "19.1.4",
|
||||
"@types/react-dom": "19.1.5",
|
||||
"react-hook-form": "^7.57.0",
|
||||
"babel-plugin-react-compiler": "19.1.0-rc.2",
|
||||
"cssnano": "^7.0.7",
|
||||
"pino-pretty": "^13.0.0",
|
||||
@@ -92,7 +94,8 @@
|
||||
"supabase": "^2.22.12",
|
||||
"tailwindcss": "4.1.7",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "^5.8.3"
|
||||
"typescript": "^5.8.3",
|
||||
"yup": "^1.6.1"
|
||||
},
|
||||
"prettier": "@kit/prettier-config",
|
||||
"browserslist": [
|
||||
@@ -100,4 +103,4 @@
|
||||
"> 0.7%",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { cn } from '../../lib/utils';
|
||||
|
||||
import { LanguageSelector } from '@kit/ui/language-selector';
|
||||
interface HeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
logo?: React.ReactNode;
|
||||
navigation?: React.ReactNode;
|
||||
@@ -25,7 +25,8 @@ export const Header: React.FC<HeaderProps> = function ({
|
||||
<div className="grid h-14 grid-cols-3 items-center">
|
||||
<div className={'mx-auto md:mx-0'}>{logo}</div>
|
||||
<div className="order-first md:order-none">{navigation}</div>
|
||||
<div className="flex items-center justify-end gap-x-2">{actions}</div>
|
||||
|
||||
<div className="flex items-center justify-end gap-x-2"><div className="max-w-[100px]"><LanguageSelector /></div>{actions}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ const buttonVariants = cva(
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
'bg-primary text-primary-foreground hover:bg-primary/90 shadow-xs',
|
||||
'bg-primary text-primary-foreground font-medium hover:bg-primary/90 shadow-xs',
|
||||
destructive:
|
||||
'bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-xs',
|
||||
outline:
|
||||
|
||||
66
pnpm-lock.yaml
generated
66
pnpm-lock.yaml
generated
@@ -101,6 +101,9 @@ importers:
|
||||
date-fns:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
fast-xml-parser:
|
||||
specifier: ^5.2.3
|
||||
version: 5.2.5
|
||||
lucide-react:
|
||||
specifier: ^0.510.0
|
||||
version: 0.510.0(react@19.1.0)
|
||||
@@ -134,9 +137,6 @@ importers:
|
||||
tailwind-merge:
|
||||
specifier: ^3.3.0
|
||||
version: 3.3.0
|
||||
xml-js:
|
||||
specifier: ^1.6.11
|
||||
version: 1.6.11
|
||||
zod:
|
||||
specifier: ^3.24.4
|
||||
version: 3.25.56
|
||||
@@ -189,6 +189,9 @@ importers:
|
||||
typescript:
|
||||
specifier: ^5.8.3
|
||||
version: 5.8.3
|
||||
yup:
|
||||
specifier: ^1.6.1
|
||||
version: 1.6.1
|
||||
|
||||
packages/analytics:
|
||||
devDependencies:
|
||||
@@ -5362,6 +5365,10 @@ packages:
|
||||
fast-uri@3.0.6:
|
||||
resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
|
||||
|
||||
fast-xml-parser@5.2.5:
|
||||
resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==}
|
||||
hasBin: true
|
||||
|
||||
fastq@1.19.1:
|
||||
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
|
||||
|
||||
@@ -6727,6 +6734,9 @@ packages:
|
||||
prop-types@15.8.1:
|
||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||
|
||||
property-expr@2.0.6:
|
||||
resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==}
|
||||
|
||||
prosemirror-commands@1.7.1:
|
||||
resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==}
|
||||
|
||||
@@ -6976,9 +6986,6 @@ packages:
|
||||
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
sax@1.4.1:
|
||||
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
|
||||
|
||||
scheduler@0.26.0:
|
||||
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
|
||||
|
||||
@@ -7176,6 +7183,9 @@ packages:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
strnum@2.1.1:
|
||||
resolution: {integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==}
|
||||
|
||||
styled-jsx@5.1.6:
|
||||
resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
@@ -7273,6 +7283,9 @@ packages:
|
||||
thread-stream@3.1.0:
|
||||
resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==}
|
||||
|
||||
tiny-case@1.0.3:
|
||||
resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==}
|
||||
|
||||
tiny-invariant@1.0.6:
|
||||
resolution: {integrity: sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==}
|
||||
|
||||
@@ -7290,6 +7303,9 @@ packages:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
|
||||
toposort@2.0.2:
|
||||
resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==}
|
||||
|
||||
totalist@3.0.1:
|
||||
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -7354,6 +7370,10 @@ packages:
|
||||
resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
type-fest@2.19.0:
|
||||
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
|
||||
engines: {node: '>=12.20'}
|
||||
|
||||
typed-array-buffer@1.0.3:
|
||||
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -7579,10 +7599,6 @@ packages:
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
xml-js@1.6.11:
|
||||
resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
|
||||
hasBin: true
|
||||
|
||||
xtend@4.0.2:
|
||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||
engines: {node: '>=0.4'}
|
||||
@@ -7639,6 +7655,9 @@ packages:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
yup@1.6.1:
|
||||
resolution: {integrity: sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==}
|
||||
|
||||
zod@3.25.56:
|
||||
resolution: {integrity: sha512-rd6eEF3BTNvQnR2e2wwolfTmUTnp70aUTqr0oaGbHifzC3BKJsoV+Gat8vxUMR1hwOKBs6El+qWehrHbCpW6SQ==}
|
||||
|
||||
@@ -12494,6 +12513,10 @@ snapshots:
|
||||
|
||||
fast-uri@3.0.6: {}
|
||||
|
||||
fast-xml-parser@5.2.5:
|
||||
dependencies:
|
||||
strnum: 2.1.1
|
||||
|
||||
fastq@1.19.1:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
@@ -13960,6 +13983,8 @@ snapshots:
|
||||
object-assign: 4.1.1
|
||||
react-is: 16.13.1
|
||||
|
||||
property-expr@2.0.6: {}
|
||||
|
||||
prosemirror-commands@1.7.1:
|
||||
dependencies:
|
||||
prosemirror-model: 1.25.1
|
||||
@@ -14266,8 +14291,6 @@ snapshots:
|
||||
|
||||
safe-stable-stringify@2.5.0: {}
|
||||
|
||||
sax@1.4.1: {}
|
||||
|
||||
scheduler@0.26.0: {}
|
||||
|
||||
schema-utils@4.3.2:
|
||||
@@ -14537,6 +14560,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/node': 22.15.30
|
||||
|
||||
strnum@2.1.1: {}
|
||||
|
||||
styled-jsx@5.1.6(@babel/core@7.27.4)(react@19.1.0):
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
@@ -14626,6 +14651,8 @@ snapshots:
|
||||
dependencies:
|
||||
real-require: 0.2.0
|
||||
|
||||
tiny-case@1.0.3: {}
|
||||
|
||||
tiny-invariant@1.0.6: {}
|
||||
|
||||
tiny-invariant@1.3.3: {}
|
||||
@@ -14641,6 +14668,8 @@ snapshots:
|
||||
dependencies:
|
||||
is-number: 7.0.0
|
||||
|
||||
toposort@2.0.2: {}
|
||||
|
||||
totalist@3.0.1: {}
|
||||
|
||||
tr46@0.0.3: {}
|
||||
@@ -14693,6 +14722,8 @@ snapshots:
|
||||
|
||||
type-fest@0.7.1: {}
|
||||
|
||||
type-fest@2.19.0: {}
|
||||
|
||||
typed-array-buffer@1.0.3:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
@@ -15006,10 +15037,6 @@ snapshots:
|
||||
|
||||
ws@8.18.2: {}
|
||||
|
||||
xml-js@1.6.11:
|
||||
dependencies:
|
||||
sax: 1.4.1
|
||||
|
||||
xtend@4.0.2: {}
|
||||
|
||||
y-prosemirror@1.3.5(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27):
|
||||
@@ -15056,6 +15083,13 @@ snapshots:
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
|
||||
yup@1.6.1:
|
||||
dependencies:
|
||||
property-expr: 2.0.6
|
||||
tiny-case: 1.0.3
|
||||
toposort: 2.0.2
|
||||
type-fest: 2.19.0
|
||||
|
||||
zod@3.25.56: {}
|
||||
|
||||
zwitch@2.0.4: {}
|
||||
|
||||
16
public/assets/MedReportSmallLogo.tsx
Normal file
16
public/assets/MedReportSmallLogo.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
export const MedReportSmallLogo = () => {
|
||||
return (
|
||||
<svg
|
||||
width="21"
|
||||
height="21"
|
||||
viewBox="0 0 21 21"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M20.7002 11.7002C15.7296 11.7002 11.7002 15.7296 11.7002 20.7002H8.10059C8.10059 13.7414 13.7414 8.10059 20.7002 8.10059V11.7002ZM12.8994 0.299805C12.8994 7.25859 7.25859 12.8994 0.299805 12.8994V9.2998C5.27037 9.2998 9.2998 5.27037 9.2998 0.299805H12.8994Z"
|
||||
fill="#0A5328"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
BIN
public/assets/med-report-logo-big.png
Normal file
BIN
public/assets/med-report-logo-big.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
public/assets/success.png
Normal file
BIN
public/assets/success.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -111,5 +111,7 @@
|
||||
"languageDescription": "Choose your preferred language",
|
||||
"noTeamsYet": "You don't have any teams yet.",
|
||||
"createTeam": "Create a team to get started.",
|
||||
"createTeamButtonLabel": "Create a Team"
|
||||
"createTeamButtonLabel": "Create a Team",
|
||||
"createCompanyAccount": "Create Company Account",
|
||||
"requestCompanyAccount": "Request Company Account"
|
||||
}
|
||||
|
||||
@@ -35,5 +35,6 @@
|
||||
"contactSuccessDescription": "We have received your message and will get back to you as soon as possible",
|
||||
"contactErrorDescription": "An error occurred while sending your message. Please try again later",
|
||||
"footerDescription": "Here you can add a description about your company or product",
|
||||
"copyright": "© Copyright {{year}} {{product}}. All Rights Reserved."
|
||||
"copyright": "© Copyright {{year}} {{product}}. All Rights Reserved.",
|
||||
"heroSubtitle": "A simple, convenient, and quick overview of your health condition"
|
||||
}
|
||||
|
||||
117
public/locales/et/account.json
Normal file
117
public/locales/et/account.json
Normal file
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"accountTabLabel": "Account Settings",
|
||||
"accountTabDescription": "Manage your account settings",
|
||||
"homePage": "Home",
|
||||
"billingTab": "Billing",
|
||||
"settingsTab": "Settings",
|
||||
"multiFactorAuth": "Multi-Factor Authentication",
|
||||
"multiFactorAuthDescription": "Set up Multi-Factor Authentication method to further secure your account",
|
||||
"updateProfileSuccess": "Profile successfully updated",
|
||||
"updateProfileError": "Encountered an error. Please try again",
|
||||
"updatePasswordSuccess": "Password update request successful",
|
||||
"updatePasswordSuccessMessage": "Your password has been successfully updated!",
|
||||
"updatePasswordError": "Encountered an error. Please try again",
|
||||
"updatePasswordLoading": "Updating password...",
|
||||
"updateProfileLoading": "Updating profile...",
|
||||
"name": "Your Name",
|
||||
"nameDescription": "Update your name to be displayed on your profile",
|
||||
"emailLabel": "Email Address",
|
||||
"accountImage": "Your Profile Picture",
|
||||
"accountImageDescription": "Please choose a photo to upload as your profile picture.",
|
||||
"profilePictureHeading": "Upload a Profile Picture",
|
||||
"profilePictureSubheading": "Choose a photo to upload as your profile picture.",
|
||||
"updateProfileSubmitLabel": "Update Profile",
|
||||
"updatePasswordCardTitle": "Update your Password",
|
||||
"updatePasswordCardDescription": "Update your password to keep your account secure.",
|
||||
"currentPassword": "Current Password",
|
||||
"newPassword": "New Password",
|
||||
"repeatPassword": "Repeat New Password",
|
||||
"repeatPasswordDescription": "Please repeat your new password to confirm it",
|
||||
"yourPassword": "Your Password",
|
||||
"updatePasswordSubmitLabel": "Update Password",
|
||||
"updateEmailCardTitle": "Update your Email",
|
||||
"updateEmailCardDescription": "Update your email address you use to login to your account",
|
||||
"newEmail": "Your New Email",
|
||||
"repeatEmail": "Repeat Email",
|
||||
"updateEmailSubmitLabel": "Update Email Address",
|
||||
"updateEmailSuccess": "Email update request successful",
|
||||
"updateEmailSuccessMessage": "We sent you an email to confirm your new email address. Please check your inbox and click on the link to confirm your new email address.",
|
||||
"updateEmailLoading": "Updating your email...",
|
||||
"updateEmailError": "Email not updated. Please try again",
|
||||
"passwordNotMatching": "Passwords do not match. Make sure you're using the correct password",
|
||||
"emailNotMatching": "Emails do not match. Make sure you're using the correct email",
|
||||
"passwordNotChanged": "Your password has not changed",
|
||||
"emailsNotMatching": "Emails do not match. Make sure you're using the correct email",
|
||||
"cannotUpdatePassword": "You cannot update your password because your account is not linked to any.",
|
||||
"setupMfaButtonLabel": "Setup a new Factor",
|
||||
"multiFactorSetupErrorHeading": "Setup Failed",
|
||||
"multiFactorSetupErrorDescription": "Sorry, there was an error while setting up your factor. Please try again.",
|
||||
"multiFactorAuthHeading": "Secure your account with Multi-Factor Authentication",
|
||||
"multiFactorModalHeading": "Use your authenticator app to scan the QR code below. Then enter the code generated.",
|
||||
"factorNameLabel": "A memorable name to identify this factor",
|
||||
"factorNameHint": "Use an easy-to-remember name to easily identify this factor in the future. Ex. iPhone 14",
|
||||
"factorNameSubmitLabel": "Set factor name",
|
||||
"unenrollTooltip": "Unenroll this factor",
|
||||
"unenrollingFactor": "Unenrolling factor...",
|
||||
"unenrollFactorSuccess": "Factor successfully unenrolled",
|
||||
"unenrollFactorError": "Unenrolling factor failed",
|
||||
"factorsListError": "Error loading factors list",
|
||||
"factorsListErrorDescription": "Sorry, we couldn't load the factors list. Please try again.",
|
||||
"factorName": "Factor Name",
|
||||
"factorType": "Type",
|
||||
"factorStatus": "Status",
|
||||
"mfaEnabledSuccessTitle": "Multi-Factor authentication is enabled",
|
||||
"mfaEnabledSuccessDescription": "Congratulations! You have successfully enrolled in the multi factor authentication process. You will now be able to access your account with a combination of your password and an authentication code sent to your phone number.",
|
||||
"verificationCode": "Verification Code",
|
||||
"addEmailAddress": "Add Email address",
|
||||
"verifyActivationCodeDescription": "Enter the 6-digit code generated by your authenticator app in the field above",
|
||||
"loadingFactors": "Loading factors...",
|
||||
"enableMfaFactor": "Enable Factor",
|
||||
"disableMfaFactor": "Disable Factor",
|
||||
"qrCodeErrorHeading": "QR Code Error",
|
||||
"qrCodeErrorDescription": "Sorry, we weren't able to generate the QR code",
|
||||
"multiFactorSetupSuccess": "Factor successfully enrolled",
|
||||
"submitVerificationCode": "Submit Verification Code",
|
||||
"mfaEnabledSuccessAlert": "Multi-Factor authentication is enabled",
|
||||
"verifyingCode": "Verifying code...",
|
||||
"invalidVerificationCodeHeading": "Invalid Verification Code",
|
||||
"invalidVerificationCodeDescription": "The verification code you entered is invalid. Please try again.",
|
||||
"unenrollFactorModalHeading": "Unenroll Factor",
|
||||
"unenrollFactorModalDescription": "You're about to unenroll this factor. You will not be able to use it to login to your account.",
|
||||
"unenrollFactorModalBody": "You're about to unenroll this factor. You will not be able to use it to login to your account.",
|
||||
"unenrollFactorModalButtonLabel": "Yes, unenroll factor",
|
||||
"selectFactor": "Choose a factor to verify your identity",
|
||||
"disableMfa": "Disable Multi-Factor Authentication",
|
||||
"disableMfaButtonLabel": "Disable MFA",
|
||||
"confirmDisableMfaButtonLabel": "Yes, disable MFA",
|
||||
"disablingMfa": "Disabling Multi-Factor Authentication. Please wait...",
|
||||
"disableMfaSuccess": "Multi-Factor Authentication successfully disabled",
|
||||
"disableMfaError": "Sorry, we encountered an error. MFA has not been disabled.",
|
||||
"sendingEmailVerificationLink": "Sending Email...",
|
||||
"sendEmailVerificationLinkSuccess": "Verification link successfully sent",
|
||||
"sendEmailVerificationLinkError": "Sorry, we weren't able to send you the email",
|
||||
"sendVerificationLinkSubmitLabel": "Send Verification Link",
|
||||
"sendVerificationLinkSuccessLabel": "Email sent! Check your Inbox",
|
||||
"verifyEmailAlertHeading": "Please verify your email to enable MFA",
|
||||
"verificationLinkAlertDescription": "Your email is not yet verified. Please verify your email to be able to set up Multi-Factor Authentication.",
|
||||
"authFactorName": "Factor Name (optional)",
|
||||
"authFactorNameHint": "Assign a name that helps you remember the phone number used",
|
||||
"loadingUser": "Loading user details. Please wait...",
|
||||
"linkPhoneNumber": "Link Phone Number",
|
||||
"dangerZone": "Danger Zone",
|
||||
"dangerZoneDescription": "Some actions cannot be undone. Please be careful.",
|
||||
"deleteAccount": "Delete your Account",
|
||||
"deletingAccount": "Deleting account. Please wait...",
|
||||
"deleteAccountDescription": "This will delete your account and the accounts you own. Furthermore, we will immediately cancel any active subscriptions. This action cannot be undone.",
|
||||
"deleteProfileConfirmationInputLabel": "Type DELETE to confirm",
|
||||
"deleteAccountErrorHeading": "Sorry, we couldn't delete your account",
|
||||
"needsReauthentication": "Reauthentication Required",
|
||||
"needsReauthenticationDescription": "You need to reauthenticate to change your password. Please sign out and sign in again to change your password.",
|
||||
"language": "Language",
|
||||
"languageDescription": "Choose your preferred language",
|
||||
"noTeamsYet": "You don't have any teams yet.",
|
||||
"createTeam": "Create a team to get started.",
|
||||
"createTeamButtonLabel": "Create a Team",
|
||||
"createCompanyAccount": "Create Company Account",
|
||||
"requestCompanyAccount": "Küsi pakkumist"
|
||||
}
|
||||
90
public/locales/et/auth.json
Normal file
90
public/locales/et/auth.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"signUpHeading": "Create an account",
|
||||
"signUp": "Sign Up",
|
||||
"signUpSubheading": "Fill the form below to create an account.",
|
||||
"signInHeading": "Sign in to your account",
|
||||
"signInSubheading": "Welcome back! Please enter your details",
|
||||
"signIn": "Sign In",
|
||||
"getStarted": "Get started",
|
||||
"updatePassword": "Update Password",
|
||||
"signOut": "Sign out",
|
||||
"signingIn": "Signing in...",
|
||||
"signingUp": "Signing up...",
|
||||
"doNotHaveAccountYet": "Do not have an account yet?",
|
||||
"alreadyHaveAnAccount": "Already have an account?",
|
||||
"signUpToAcceptInvite": "Please sign in/up to accept the invite",
|
||||
"clickToAcceptAs": "Click the button below to accept the invite with as <b>{{email}}</b>",
|
||||
"acceptInvite": "Accept invite",
|
||||
"acceptingInvite": "Accepting Invite...",
|
||||
"acceptInviteSuccess": "Invite successfully accepted",
|
||||
"acceptInviteError": "Error encountered while accepting invite",
|
||||
"acceptInviteWithDifferentAccount": "Want to accept the invite with a different account?",
|
||||
"alreadyHaveAccountStatement": "I already have an account, I want to sign in instead",
|
||||
"doNotHaveAccountStatement": "I do not have an account, I want to sign up instead",
|
||||
"signInWithProvider": "Sign in with {{provider}}",
|
||||
"signInWithPhoneNumber": "Sign in with Phone Number",
|
||||
"signInWithEmail": "Sign in with Email",
|
||||
"signUpWithEmail": "Sign up with Email",
|
||||
"passwordHint": "Ensure it's at least 8 characters",
|
||||
"repeatPasswordHint": "Type your password again",
|
||||
"repeatPassword": "Repeat password",
|
||||
"passwordForgottenQuestion": "Password forgotten?",
|
||||
"passwordResetLabel": "Reset Password",
|
||||
"passwordResetSubheading": "Enter your email address below. You will receive a link to reset your password.",
|
||||
"passwordResetSuccessMessage": "Check your Inbox! We emailed you a link for resetting your Password.",
|
||||
"passwordRecoveredQuestion": "Password recovered?",
|
||||
"passwordLengthError": "Please provide a password with at least 6 characters",
|
||||
"sendEmailLink": "Send Email Link",
|
||||
"sendingEmailLink": "Sending Email Link...",
|
||||
"sendLinkSuccessDescription": "Check your email, we just sent you a link. Follow the link to sign in.",
|
||||
"sendLinkSuccess": "We sent you a link by email",
|
||||
"sendLinkSuccessToast": "Link successfully sent",
|
||||
"getNewLink": "Get a new link",
|
||||
"verifyCodeHeading": "Verify your account",
|
||||
"verificationCode": "Verification Code",
|
||||
"verificationCodeHint": "Enter the code we sent you by SMS",
|
||||
"verificationCodeSubmitButtonLabel": "Submit Verification Code",
|
||||
"sendingMfaCode": "Sending Verification Code...",
|
||||
"verifyingMfaCode": "Verifying code...",
|
||||
"sendMfaCodeError": "Sorry, we couldn't send you a verification code",
|
||||
"verifyMfaCodeSuccess": "Code verified! Signing you in...",
|
||||
"verifyMfaCodeError": "Ops! It looks like the code is not correct",
|
||||
"reauthenticate": "Reauthenticate",
|
||||
"reauthenticateDescription": "For security reasons, we need you to re-authenticate",
|
||||
"errorAlertHeading": "Sorry, we could not authenticate you",
|
||||
"emailConfirmationAlertHeading": "We sent you a confirmation email.",
|
||||
"emailConfirmationAlertBody": "Welcome! Please check your email and click the link to verify your account.",
|
||||
"resendLink": "Resend link",
|
||||
"resendLinkSuccessDescription": "We sent you a new link to your email! Follow the link to sign in.",
|
||||
"resendLinkSuccess": "Check your email!",
|
||||
"authenticationErrorAlertHeading": "Authentication Error",
|
||||
"authenticationErrorAlertBody": "Sorry, we could not authenticate you. Please try again.",
|
||||
"sendEmailCode": "Get code to your Email",
|
||||
"sendingEmailCode": "Sending code...",
|
||||
"resetPasswordError": "Sorry, we could not reset your password. Please try again.",
|
||||
"emailPlaceholder": "your@email.com",
|
||||
"inviteAlertHeading": "You have been invited to join a team",
|
||||
"inviteAlertBody": "Please sign in or sign up to accept the invite and join the team.",
|
||||
"acceptTermsAndConditions": "I accept the <TermsOfServiceLink /> and <PrivacyPolicyLink />",
|
||||
"termsOfService": "Terms of Service",
|
||||
"privacyPolicy": "Privacy Policy",
|
||||
"orContinueWith": "Or continue with",
|
||||
"redirecting": "You're in! Please wait...",
|
||||
"errors": {
|
||||
"Invalid login credentials": "The credentials entered are invalid",
|
||||
"User already registered": "This credential is already in use. Please try with another one.",
|
||||
"Email not confirmed": "Please confirm your email address before signing in",
|
||||
"default": "We have encountered an error. Please ensure you have a working internet connection and try again",
|
||||
"generic": "Sorry, we weren't able to authenticate you. Please try again.",
|
||||
"link": "Sorry, we encountered an error while sending your link. Please try again.",
|
||||
"codeVerifierMismatch": "It looks like you're trying to sign in using a different browser than the one you used to request the sign in link. Please try again using the same browser.",
|
||||
"minPasswordLength": "Password must be at least 8 characters long",
|
||||
"passwordsDoNotMatch": "The passwords do not match",
|
||||
"minPasswordNumbers": "Password must contain at least one number",
|
||||
"minPasswordSpecialChars": "Password must contain at least one special character",
|
||||
"uppercasePassword": "Password must contain at least one uppercase letter",
|
||||
"insufficient_aal": "Please sign-in with your current multi-factor authentication to perform this action",
|
||||
"otp_expired": "The email link has expired. Please try again.",
|
||||
"same_password": "The password cannot be the same as the current password"
|
||||
}
|
||||
}
|
||||
120
public/locales/et/billing.json
Normal file
120
public/locales/et/billing.json
Normal file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"subscriptionTabSubheading": "Manage your Subscription and Billing",
|
||||
"planCardTitle": "Your Plan",
|
||||
"planCardDescription": "Below are the details of your current plan. You can change your plan or cancel your subscription at any time.",
|
||||
"planRenewal": "Renews every {{interval}} at {{price}}",
|
||||
"planDetails": "Plan Details",
|
||||
"checkout": "Proceed to Checkout",
|
||||
"trialEndsOn": "Your trial ends on",
|
||||
"billingPortalCardButton": "Visit Billing Portal",
|
||||
"billingPortalCardTitle": "Manage your Billing Details",
|
||||
"billingPortalCardDescription": "Visit your Billing Portal to manage your subscription and billing. You can update or cancel your plan, or download your invoices.",
|
||||
"cancelAtPeriodEndDescription": "Your subscription is scheduled to be canceled on {{- endDate }}.",
|
||||
"renewAtPeriodEndDescription": "Your subscription is scheduled to be renewed on {{- endDate }}",
|
||||
"noPermissionsAlertHeading": "You don't have permissions to change the billing settings",
|
||||
"noPermissionsAlertBody": "Please contact your account owner to change the billing settings for your account.",
|
||||
"checkoutSuccessTitle": "Done! You're all set.",
|
||||
"checkoutSuccessDescription": "Thank you for subscribing, we have successfully processed your subscription! A confirmation email will be sent to {{ customerEmail }}.",
|
||||
"checkoutSuccessBackButton": "Proceed to App",
|
||||
"cannotManageBillingAlertTitle": "You cannot manage billing",
|
||||
"cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account owner.",
|
||||
"manageTeamPlan": "Manage your Team Plan",
|
||||
"manageTeamPlanDescription": "Choose a plan that fits your team's needs. You can upgrade or downgrade your plan at any time.",
|
||||
"basePlan": "Base Plan",
|
||||
"billingInterval": {
|
||||
"label": "Choose your billing interval",
|
||||
"month": "Billed monthly",
|
||||
"year": "Billed yearly"
|
||||
},
|
||||
"perMonth": "month",
|
||||
"custom": "Custom Plan",
|
||||
"lifetime": "Lifetime",
|
||||
"trialPeriod": "{{period}} day trial",
|
||||
"perPeriod": "per {{period}}",
|
||||
"redirectingToPayment": "Redirecting to checkout. Please wait...",
|
||||
"proceedToPayment": "Proceed to Payment",
|
||||
"startTrial": "Start Trial",
|
||||
"perTeamMember": "Per team member",
|
||||
"perUnit": "Per {{unit}} usage",
|
||||
"teamMembers": "Team Members",
|
||||
"includedUpTo": "Up to {{upTo}} {{unit}} included in the plan",
|
||||
"fromPreviousTierUpTo": "for each {{unit}} for the next {{ upTo }} {{ unit }}",
|
||||
"andAbove": "above {{ previousTier }} {{ unit }}",
|
||||
"startingAtPriceUnit": "Starting at {{price}}/{{unit}}",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"forEveryUnit": "for every {{ unit }}",
|
||||
"setupFee": "plus a {{ setupFee }} setup fee",
|
||||
"perUnitIncluded": "({{included}} included)",
|
||||
"featuresLabel": "Features",
|
||||
"detailsLabel": "Details",
|
||||
"planPickerLabel": "Pick your preferred plan",
|
||||
"planCardLabel": "Manage your Plan",
|
||||
"planPickerAlertErrorTitle": "Error requesting checkout",
|
||||
"planPickerAlertErrorDescription": "There was an error requesting checkout. Please try again later.",
|
||||
"subscriptionCancelled": "Subscription Cancelled",
|
||||
"cancelSubscriptionDate": "Your subscription will be cancelled at the end of the period",
|
||||
"noPlanChosen": "Please choose a plan",
|
||||
"noIntervalPlanChosen": "Please choose a billing interval",
|
||||
"status": {
|
||||
"free": {
|
||||
"badge": "Free Plan",
|
||||
"heading": "You are currently on the Free Plan",
|
||||
"description": "You're on a free plan. You can upgrade to a paid plan at any time."
|
||||
},
|
||||
"active": {
|
||||
"badge": "Active",
|
||||
"heading": "Your subscription is active",
|
||||
"description": "Your subscription is active. You can manage your subscription and billing in the Customer Portal."
|
||||
},
|
||||
"trialing": {
|
||||
"badge": "Trial",
|
||||
"heading": "You're on a trial",
|
||||
"description": "You can enjoy the benefits of plan until the trial ends"
|
||||
},
|
||||
"past_due": {
|
||||
"badge": "Past Due",
|
||||
"heading": "Your invoice is past due",
|
||||
"description": "Your invoice is past due. Please update your payment method."
|
||||
},
|
||||
"canceled": {
|
||||
"badge": "Canceled",
|
||||
"heading": "Your subscription is canceled",
|
||||
"description": "Your subscription is canceled. It is scheduled to end at end of the billing period."
|
||||
},
|
||||
"unpaid": {
|
||||
"badge": "Unpaid",
|
||||
"heading": "Your invoice is unpaid",
|
||||
"description": "Your invoice is unpaid. Please update your payment method."
|
||||
},
|
||||
"incomplete": {
|
||||
"badge": "Incomplete",
|
||||
"heading": "We're waiting for your payment",
|
||||
"description": "We're waiting for your payment to go through. Please bear with us."
|
||||
},
|
||||
"incomplete_expired": {
|
||||
"badge": "Expired",
|
||||
"heading": "Your payment has expired",
|
||||
"description": "Your payment has expired. Please update your payment method."
|
||||
},
|
||||
"paused": {
|
||||
"badge": "Paused",
|
||||
"heading": "Your subscription is paused",
|
||||
"description": "Your subscription is paused. You can resume it at any time."
|
||||
},
|
||||
"succeeded": {
|
||||
"badge": "Succeeded",
|
||||
"heading": "Your payment was successful",
|
||||
"description": "Your payment was successful. Thank you for subscribing!"
|
||||
},
|
||||
"pending": {
|
||||
"badge": "Pending",
|
||||
"heading": "Your payment is pending",
|
||||
"description": "Your payment is pending. Please bear with us."
|
||||
},
|
||||
"failed": {
|
||||
"badge": "Failed",
|
||||
"heading": "Your payment failed",
|
||||
"description": "Your payment failed. Please update your payment method."
|
||||
}
|
||||
}
|
||||
}
|
||||
96
public/locales/et/common.json
Normal file
96
public/locales/et/common.json
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"homeTabLabel": "Home",
|
||||
"homeTabDescription": "Welcome to your home page",
|
||||
"accountMembers": "Team Members",
|
||||
"membersTabDescription": "Here you can manage the members of your team.",
|
||||
"billingTabLabel": "Billing",
|
||||
"billingTabDescription": "Manage your billing and subscription",
|
||||
"dashboardTabLabel": "Dashboard",
|
||||
"settingsTabLabel": "Settings",
|
||||
"profileSettingsTabLabel": "Profile",
|
||||
"subscriptionSettingsTabLabel": "Subscription",
|
||||
"dashboardTabDescription": "An overview of your account's activity and performance across all your projects.",
|
||||
"settingsTabDescription": "Manage your settings and preferences.",
|
||||
"emailAddress": "Email Address",
|
||||
"password": "Password",
|
||||
"modalConfirmationQuestion": "Are you sure you want to continue?",
|
||||
"imageInputLabel": "Click here to upload an image",
|
||||
"cancel": "Cancel",
|
||||
"clear": "Clear",
|
||||
"notFound": "Not Found",
|
||||
"backToHomePage": "Back to Home Page",
|
||||
"goBack": "Go Back",
|
||||
"genericServerError": "Sorry, something went wrong.",
|
||||
"genericServerErrorHeading": "Sorry, something went wrong while processing your request. Please contact us if the issue persists.",
|
||||
"pageNotFound": "Sorry, this page does not exist.",
|
||||
"pageNotFoundSubHeading": "Apologies, the page you were looking for was not found",
|
||||
"genericError": "Sorry, something went wrong.",
|
||||
"genericErrorSubHeading": "Apologies, an error occurred while processing your request. Please contact us if the issue persists.",
|
||||
"anonymousUser": "Anonymous",
|
||||
"tryAgain": "Try Again",
|
||||
"theme": "Theme",
|
||||
"lightTheme": "Light",
|
||||
"darkTheme": "Dark",
|
||||
"systemTheme": "System",
|
||||
"expandSidebar": "Expand Sidebar",
|
||||
"collapseSidebar": "Collapse Sidebar",
|
||||
"documentation": "Documentation",
|
||||
"getStarted": "Get Started",
|
||||
"getStartedWithPlan": "Get Started with {{plan}}",
|
||||
"retry": "Retry",
|
||||
"contactUs": "Contact Us",
|
||||
"loading": "Loading. Please wait...",
|
||||
"yourAccounts": "Your Accounts",
|
||||
"continue": "Continue",
|
||||
"skip": "Skip",
|
||||
"signedInAs": "Signed in as",
|
||||
"pageOfPages": "Page {{page}} of {{total}}",
|
||||
"noData": "No data available",
|
||||
"pageNotFoundHeading": "Ouch! :|",
|
||||
"errorPageHeading": "Ouch! :|",
|
||||
"notifications": "Notifications",
|
||||
"noNotifications": "No notifications",
|
||||
"justNow": "Just now",
|
||||
"newVersionAvailable": "New version available",
|
||||
"newVersionAvailableDescription": "A new version of the app is available. It is recommended to refresh the page to get the latest updates and avoid any issues.",
|
||||
"newVersionSubmitButton": "Reload and Update",
|
||||
"back": "Back",
|
||||
"routes": {
|
||||
"home": "Home",
|
||||
"account": "Account",
|
||||
"members": "Members",
|
||||
"billing": "Billing",
|
||||
"dashboard": "Dashboard",
|
||||
"settings": "Settings",
|
||||
"profile": "Profile",
|
||||
"application": "Application"
|
||||
},
|
||||
"roles": {
|
||||
"owner": {
|
||||
"label": "Owner"
|
||||
},
|
||||
"member": {
|
||||
"label": "Member"
|
||||
}
|
||||
},
|
||||
"otp": {
|
||||
"requestVerificationCode": "Request Verification Code",
|
||||
"requestVerificationCodeDescription": "We must verify your identity to continue with this action. We'll send a verification code to the email address {{email}}.",
|
||||
"sendingCode": "Sending Code...",
|
||||
"sendVerificationCode": "Send Verification Code",
|
||||
"enterVerificationCode": "Enter Verification Code",
|
||||
"codeSentToEmail": "We've sent a verification code to the email address {{email}}.",
|
||||
"verificationCode": "Verification Code",
|
||||
"enterCodeFromEmail": "Enter the 6-digit code we sent to your email.",
|
||||
"verifying": "Verifying...",
|
||||
"verifyCode": "Verify Code",
|
||||
"requestNewCode": "Request New Code",
|
||||
"errorSendingCode": "Error sending code. Please try again."
|
||||
},
|
||||
"cookieBanner": {
|
||||
"title": "Hey, we use cookies 🍪",
|
||||
"description": "This website uses cookies to ensure you get the best experience on our website.",
|
||||
"reject": "Reject",
|
||||
"accept": "Accept"
|
||||
}
|
||||
}
|
||||
40
public/locales/et/marketing.json
Normal file
40
public/locales/et/marketing.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"blog": "Blog",
|
||||
"blogSubtitle": "News and updates about the platform",
|
||||
"documentation": "Documentation",
|
||||
"documentationSubtitle": "Tutorials and guide to get started with the platform",
|
||||
"faq": "FAQ",
|
||||
"faqSubtitle": "Frequently asked questions about the platform",
|
||||
"pricing": "Pricing",
|
||||
"pricingSubtitle": "Pricing plans and payment options",
|
||||
"backToBlog": "Back to blog",
|
||||
"noPosts": "No posts found",
|
||||
"blogPaginationNext": "Next Page",
|
||||
"blogPaginationPrevious": "Previous Page",
|
||||
"readMore": "Read more",
|
||||
"contactFaq": "If you have any questions, please contact us",
|
||||
"contact": "Contact",
|
||||
"about": "About",
|
||||
"product": "Product",
|
||||
"legal": "Legal",
|
||||
"termsOfService": "Terms of Service",
|
||||
"termsOfServiceDescription": "Our terms and conditions",
|
||||
"cookiePolicy": "Cookie Policy",
|
||||
"cookiePolicyDescription": "Our cookie policy and how we use them",
|
||||
"privacyPolicy": "Privacy Policy",
|
||||
"privacyPolicyDescription": "Our privacy policy and how we use your data",
|
||||
"contactDescription": "Contact us for any questions or feedback",
|
||||
"contactHeading": "Send us a message",
|
||||
"contactSubheading": "We will get back to you as soon as possible",
|
||||
"contactName": "Your Name",
|
||||
"contactEmail": "Your Email",
|
||||
"contactMessage": "Your Message",
|
||||
"sendMessage": "Send Message",
|
||||
"contactSuccess": "Your message has been sent successfully",
|
||||
"contactError": "An error occurred while sending your message",
|
||||
"contactSuccessDescription": "We have received your message and will get back to you as soon as possible",
|
||||
"contactErrorDescription": "An error occurred while sending your message. Please try again later",
|
||||
"footerDescription": "Here you can add a description about your company or product",
|
||||
"copyright": "© Copyright {{year}} {{product}}. All Rights Reserved.",
|
||||
"heroSubtitle": "Lihtne, mugav ja kiire ülevaade Sinu tervise seisundist"
|
||||
}
|
||||
163
public/locales/et/teams.json
Normal file
163
public/locales/et/teams.json
Normal file
@@ -0,0 +1,163 @@
|
||||
{
|
||||
"home": {
|
||||
"pageTitle": "Home"
|
||||
},
|
||||
"settings": {
|
||||
"pageTitle": "Settings",
|
||||
"pageDescription": "Manage your Team details",
|
||||
"teamLogo": "Team Logo",
|
||||
"teamLogoDescription": "Update your team's logo to make it easier to identify",
|
||||
"teamName": "Team Name",
|
||||
"teamNameDescription": "Update your team's name",
|
||||
"dangerZone": "Danger Zone",
|
||||
"dangerZoneDescription": "This section contains actions that are irreversible"
|
||||
},
|
||||
"members": {
|
||||
"pageTitle": "Members"
|
||||
},
|
||||
"billing": {
|
||||
"pageTitle": "Billing"
|
||||
},
|
||||
"yourTeams": "Your Teams ({{teamsCount}})",
|
||||
"createTeam": "Create a Team",
|
||||
"creatingTeam": "Creating Team...",
|
||||
"personalAccount": "Personal Account",
|
||||
"searchAccount": "Search Account...",
|
||||
"membersTabLabel": "Members",
|
||||
"memberName": "Name",
|
||||
"youLabel": "You",
|
||||
"emailLabel": "Email",
|
||||
"roleLabel": "Role",
|
||||
"primaryOwnerLabel": "Primary Owner",
|
||||
"joinedAtLabel": "Joined at",
|
||||
"invitedAtLabel": "Invited at",
|
||||
"inviteMembersPageSubheading": "Invite members to your Team",
|
||||
"createTeamModalHeading": "Create Team",
|
||||
"createTeamModalDescription": "Create a new Team to manage your projects and members.",
|
||||
"teamNameLabel": "Team Name",
|
||||
"teamNameDescription": "Your team name should be unique and descriptive",
|
||||
"createTeamSubmitLabel": "Create Team",
|
||||
"createTeamSuccess": "Team created successfully",
|
||||
"createTeamError": "Team not created. Please try again.",
|
||||
"createTeamLoading": "Creating team...",
|
||||
"settingsPageLabel": "General",
|
||||
"createTeamDropdownLabel": "New team",
|
||||
"changeRole": "Change Role",
|
||||
"removeMember": "Remove from Account",
|
||||
"inviteMembersSuccess": "Members invited successfully!",
|
||||
"inviteMembersError": "Sorry, we encountered an error! Please try again",
|
||||
"inviteMembersLoading": "Inviting members...",
|
||||
"removeInviteButtonLabel": "Remove invite",
|
||||
"addAnotherMemberButtonLabel": "Add another one",
|
||||
"inviteMembersButtonLabel": "Send Invites",
|
||||
"removeMemberModalHeading": "You are removing this user",
|
||||
"removeMemberModalDescription": "Remove this member from the team. They will no longer have access to the team.",
|
||||
"removeMemberSuccessMessage": "Member removed successfully",
|
||||
"removeMemberErrorMessage": "Sorry, we encountered an error. Please try again",
|
||||
"removeMemberErrorHeading": "Sorry, we couldn't remove the selected member.",
|
||||
"removeMemberLoadingMessage": "Removing member...",
|
||||
"removeMemberSubmitLabel": "Remove User from Team",
|
||||
"chooseDifferentRoleError": "Role is the same as the current one",
|
||||
"updateRole": "Update Role",
|
||||
"updateRoleLoadingMessage": "Updating role...",
|
||||
"updateRoleSuccessMessage": "Role updated successfully",
|
||||
"updatingRoleErrorMessage": "Sorry, we encountered an error. Please try again.",
|
||||
"updateMemberRoleModalHeading": "Update Member's Role",
|
||||
"updateMemberRoleModalDescription": "Change the role of the selected member. The role determines the permissions of the member.",
|
||||
"roleMustBeDifferent": "Role must be different from the current one",
|
||||
"memberRoleInputLabel": "Member role",
|
||||
"updateRoleDescription": "Pick a role for this member.",
|
||||
"updateRoleSubmitLabel": "Update Role",
|
||||
"transferOwnership": "Transfer Ownership",
|
||||
"transferOwnershipDescription": "Transfer ownership of the team to another member.",
|
||||
"transferOwnershipInputLabel": "Please type TRANSFER to confirm the transfer of ownership.",
|
||||
"transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the team.",
|
||||
"deleteInvitation": "Delete Invitation",
|
||||
"deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the team.",
|
||||
"deleteInviteSuccessMessage": "Invite deleted successfully",
|
||||
"deleteInviteErrorMessage": "Invite not deleted. Please try again.",
|
||||
"deleteInviteLoadingMessage": "Deleting invite. Please wait...",
|
||||
"confirmDeletingMemberInvite": "You are deleting the invite to <b>{{ email }}</b>",
|
||||
"transferOwnershipDisclaimer": "You are transferring ownership of the selected team to <b>{{ member }}</b>.",
|
||||
"transferringOwnership": "Transferring ownership...",
|
||||
"transferOwnershipSuccess": "Ownership successfully transferred",
|
||||
"transferOwnershipError": "Sorry, we could not transfer ownership to the selected member. Please try again.",
|
||||
"deleteInviteSubmitLabel": "Delete Invite",
|
||||
"youBadgeLabel": "You",
|
||||
"updateTeamLoadingMessage": "Updating Team...",
|
||||
"updateTeamSuccessMessage": "Team successfully updated",
|
||||
"updateTeamErrorMessage": "Could not update Team. Please try again.",
|
||||
"updateLogoErrorMessage": "Could not update Logo. Please try again.",
|
||||
"teamNameInputLabel": "Team Name",
|
||||
"teamLogoInputHeading": "Upload your team's Logo",
|
||||
"teamLogoInputSubheading": "Please choose a photo to upload as your team logo.",
|
||||
"updateTeamSubmitLabel": "Update Team",
|
||||
"inviteMembersHeading": "Invite Members to your Team",
|
||||
"inviteMembersDescription": "Invite members to your team by entering their email and role.",
|
||||
"emailPlaceholder": "member@email.com",
|
||||
"membersPageHeading": "Members",
|
||||
"inviteMembersButton": "Invite Members",
|
||||
"invitingMembers": "Inviting members...",
|
||||
"inviteMembersSuccessMessage": "Members invited successfully",
|
||||
"inviteMembersErrorMessage": "Sorry, members could not be invited. Please try again.",
|
||||
"pendingInvitesHeading": "Pending Invites",
|
||||
"pendingInvitesDescription": " Here you can manage the pending invitations to your team.",
|
||||
"noPendingInvites": "No pending invites found",
|
||||
"loadingMembers": "Loading members...",
|
||||
"loadMembersError": "Sorry, we couldn't fetch your team's members.",
|
||||
"loadInvitedMembersError": "Sorry, we couldn't fetch your team's invited members.",
|
||||
"loadingInvitedMembers": "Loading invited members...",
|
||||
"invitedBadge": "Invited",
|
||||
"duplicateInviteEmailError": "You have already entered this email address",
|
||||
"invitingOwnAccountError": "Hey, that's your email!",
|
||||
"dangerZone": "Danger Zone",
|
||||
"dangerZoneSubheading": "Delete or leave your team",
|
||||
"deleteTeam": "Delete Team",
|
||||
"deleteTeamDescription": "This action cannot be undone. All data associated with this team will be deleted.",
|
||||
"deletingTeam": "Deleting team",
|
||||
"deleteTeamModalHeading": "Deleting Team",
|
||||
"deletingTeamDescription": "You are about to delete the team {{ teamName }}. This action cannot be undone.",
|
||||
"deleteTeamInputField": "Type the name of the team to confirm",
|
||||
"leaveTeam": "Leave Team",
|
||||
"leavingTeamModalHeading": "Leaving Team",
|
||||
"leavingTeamModalDescription": "You are about to leave this team. You will no longer have access to it.",
|
||||
"leaveTeamDescription": "Click the button below to leave the team. Remember, you will no longer have access to it and will need to be re-invited to join.",
|
||||
"deleteTeamDisclaimer": "You are deleting the team {{ teamName }}. This action cannot be undone.",
|
||||
"leaveTeamDisclaimer": "You are leaving the team {{ teamName }}. You will no longer have access to it.",
|
||||
"deleteTeamErrorHeading": "Sorry, we couldn't delete your team.",
|
||||
"leaveTeamErrorHeading": "Sorry, we couldn't leave your team.",
|
||||
"searchMembersPlaceholder": "Search members",
|
||||
"createTeamErrorHeading": "Sorry, we couldn't create your team.",
|
||||
"createTeamErrorMessage": "We encountered an error creating your team. Please try again.",
|
||||
"transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your team.",
|
||||
"transferTeamErrorMessage": "We encountered an error transferring ownership of your team. Please try again.",
|
||||
"updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected member.",
|
||||
"updateRoleErrorMessage": "We encountered an error updating the role of the selected member. Please try again.",
|
||||
"searchInvitations": "Search Invitations",
|
||||
"updateInvitation": "Update Invitation",
|
||||
"removeInvitation": "Remove Invitation",
|
||||
"acceptInvitation": "Accept Invitation",
|
||||
"renewInvitation": "Renew Invitation",
|
||||
"resendInvitation": "Resend Invitation",
|
||||
"expiresAtLabel": "Expires at",
|
||||
"expired": "Expired",
|
||||
"active": "Active",
|
||||
"inviteStatus": "Status",
|
||||
"inviteNotFoundOrExpired": "Invite not found or expired",
|
||||
"inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the team owner to renew the invite.",
|
||||
"backToHome": "Back to Home",
|
||||
"renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the team.",
|
||||
"renewInvitationErrorTitle": "Sorry, we couldn't renew the invitation.",
|
||||
"renewInvitationErrorDescription": "We encountered an error renewing the invitation. Please try again.",
|
||||
"signInWithDifferentAccount": "Sign in with a different account",
|
||||
"signInWithDifferentAccountDescription": "If you wish to accept the invitation with a different account, please sign out and back in with the account you wish to use.",
|
||||
"acceptInvitationHeading": "Accept Invitation to join {{accountName}}",
|
||||
"acceptInvitationDescription": "You have been invited to join the team {{accountName}}. If you wish to accept the invitation, please click the button below.",
|
||||
"continueAs": "Continue as {{email}}",
|
||||
"joinTeamAccount": "Join Team",
|
||||
"joiningTeam": "Joining team...",
|
||||
"leaveTeamInputLabel": "Please type LEAVE to confirm leaving the team.",
|
||||
"leaveTeamInputDescription": "By leaving the team, you will no longer have access to it.",
|
||||
"reservedNameError": "This name is reserved. Please choose a different one.",
|
||||
"specialCharactersError": "This name cannot contain special characters. Please choose a different one."
|
||||
}
|
||||
117
public/locales/ru/account.json
Normal file
117
public/locales/ru/account.json
Normal file
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"accountTabLabel": "Account Settings",
|
||||
"accountTabDescription": "Manage your account settings",
|
||||
"homePage": "Home",
|
||||
"billingTab": "Billing",
|
||||
"settingsTab": "Settings",
|
||||
"multiFactorAuth": "Multi-Factor Authentication",
|
||||
"multiFactorAuthDescription": "Set up Multi-Factor Authentication method to further secure your account",
|
||||
"updateProfileSuccess": "Profile successfully updated",
|
||||
"updateProfileError": "Encountered an error. Please try again",
|
||||
"updatePasswordSuccess": "Password update request successful",
|
||||
"updatePasswordSuccessMessage": "Your password has been successfully updated!",
|
||||
"updatePasswordError": "Encountered an error. Please try again",
|
||||
"updatePasswordLoading": "Updating password...",
|
||||
"updateProfileLoading": "Updating profile...",
|
||||
"name": "Your Name",
|
||||
"nameDescription": "Update your name to be displayed on your profile",
|
||||
"emailLabel": "Email Address",
|
||||
"accountImage": "Your Profile Picture",
|
||||
"accountImageDescription": "Please choose a photo to upload as your profile picture.",
|
||||
"profilePictureHeading": "Upload a Profile Picture",
|
||||
"profilePictureSubheading": "Choose a photo to upload as your profile picture.",
|
||||
"updateProfileSubmitLabel": "Update Profile",
|
||||
"updatePasswordCardTitle": "Update your Password",
|
||||
"updatePasswordCardDescription": "Update your password to keep your account secure.",
|
||||
"currentPassword": "Current Password",
|
||||
"newPassword": "New Password",
|
||||
"repeatPassword": "Repeat New Password",
|
||||
"repeatPasswordDescription": "Please repeat your new password to confirm it",
|
||||
"yourPassword": "Your Password",
|
||||
"updatePasswordSubmitLabel": "Update Password",
|
||||
"updateEmailCardTitle": "Update your Email",
|
||||
"updateEmailCardDescription": "Update your email address you use to login to your account",
|
||||
"newEmail": "Your New Email",
|
||||
"repeatEmail": "Repeat Email",
|
||||
"updateEmailSubmitLabel": "Update Email Address",
|
||||
"updateEmailSuccess": "Email update request successful",
|
||||
"updateEmailSuccessMessage": "We sent you an email to confirm your new email address. Please check your inbox and click on the link to confirm your new email address.",
|
||||
"updateEmailLoading": "Updating your email...",
|
||||
"updateEmailError": "Email not updated. Please try again",
|
||||
"passwordNotMatching": "Passwords do not match. Make sure you're using the correct password",
|
||||
"emailNotMatching": "Emails do not match. Make sure you're using the correct email",
|
||||
"passwordNotChanged": "Your password has not changed",
|
||||
"emailsNotMatching": "Emails do not match. Make sure you're using the correct email",
|
||||
"cannotUpdatePassword": "You cannot update your password because your account is not linked to any.",
|
||||
"setupMfaButtonLabel": "Setup a new Factor",
|
||||
"multiFactorSetupErrorHeading": "Setup Failed",
|
||||
"multiFactorSetupErrorDescription": "Sorry, there was an error while setting up your factor. Please try again.",
|
||||
"multiFactorAuthHeading": "Secure your account with Multi-Factor Authentication",
|
||||
"multiFactorModalHeading": "Use your authenticator app to scan the QR code below. Then enter the code generated.",
|
||||
"factorNameLabel": "A memorable name to identify this factor",
|
||||
"factorNameHint": "Use an easy-to-remember name to easily identify this factor in the future. Ex. iPhone 14",
|
||||
"factorNameSubmitLabel": "Set factor name",
|
||||
"unenrollTooltip": "Unenroll this factor",
|
||||
"unenrollingFactor": "Unenrolling factor...",
|
||||
"unenrollFactorSuccess": "Factor successfully unenrolled",
|
||||
"unenrollFactorError": "Unenrolling factor failed",
|
||||
"factorsListError": "Error loading factors list",
|
||||
"factorsListErrorDescription": "Sorry, we couldn't load the factors list. Please try again.",
|
||||
"factorName": "Factor Name",
|
||||
"factorType": "Type",
|
||||
"factorStatus": "Status",
|
||||
"mfaEnabledSuccessTitle": "Multi-Factor authentication is enabled",
|
||||
"mfaEnabledSuccessDescription": "Congratulations! You have successfully enrolled in the multi factor authentication process. You will now be able to access your account with a combination of your password and an authentication code sent to your phone number.",
|
||||
"verificationCode": "Verification Code",
|
||||
"addEmailAddress": "Add Email address",
|
||||
"verifyActivationCodeDescription": "Enter the 6-digit code generated by your authenticator app in the field above",
|
||||
"loadingFactors": "Loading factors...",
|
||||
"enableMfaFactor": "Enable Factor",
|
||||
"disableMfaFactor": "Disable Factor",
|
||||
"qrCodeErrorHeading": "QR Code Error",
|
||||
"qrCodeErrorDescription": "Sorry, we weren't able to generate the QR code",
|
||||
"multiFactorSetupSuccess": "Factor successfully enrolled",
|
||||
"submitVerificationCode": "Submit Verification Code",
|
||||
"mfaEnabledSuccessAlert": "Multi-Factor authentication is enabled",
|
||||
"verifyingCode": "Verifying code...",
|
||||
"invalidVerificationCodeHeading": "Invalid Verification Code",
|
||||
"invalidVerificationCodeDescription": "The verification code you entered is invalid. Please try again.",
|
||||
"unenrollFactorModalHeading": "Unenroll Factor",
|
||||
"unenrollFactorModalDescription": "You're about to unenroll this factor. You will not be able to use it to login to your account.",
|
||||
"unenrollFactorModalBody": "You're about to unenroll this factor. You will not be able to use it to login to your account.",
|
||||
"unenrollFactorModalButtonLabel": "Yes, unenroll factor",
|
||||
"selectFactor": "Choose a factor to verify your identity",
|
||||
"disableMfa": "Disable Multi-Factor Authentication",
|
||||
"disableMfaButtonLabel": "Disable MFA",
|
||||
"confirmDisableMfaButtonLabel": "Yes, disable MFA",
|
||||
"disablingMfa": "Disabling Multi-Factor Authentication. Please wait...",
|
||||
"disableMfaSuccess": "Multi-Factor Authentication successfully disabled",
|
||||
"disableMfaError": "Sorry, we encountered an error. MFA has not been disabled.",
|
||||
"sendingEmailVerificationLink": "Sending Email...",
|
||||
"sendEmailVerificationLinkSuccess": "Verification link successfully sent",
|
||||
"sendEmailVerificationLinkError": "Sorry, we weren't able to send you the email",
|
||||
"sendVerificationLinkSubmitLabel": "Send Verification Link",
|
||||
"sendVerificationLinkSuccessLabel": "Email sent! Check your Inbox",
|
||||
"verifyEmailAlertHeading": "Please verify your email to enable MFA",
|
||||
"verificationLinkAlertDescription": "Your email is not yet verified. Please verify your email to be able to set up Multi-Factor Authentication.",
|
||||
"authFactorName": "Factor Name (optional)",
|
||||
"authFactorNameHint": "Assign a name that helps you remember the phone number used",
|
||||
"loadingUser": "Loading user details. Please wait...",
|
||||
"linkPhoneNumber": "Link Phone Number",
|
||||
"dangerZone": "Danger Zone",
|
||||
"dangerZoneDescription": "Some actions cannot be undone. Please be careful.",
|
||||
"deleteAccount": "Delete your Account",
|
||||
"deletingAccount": "Deleting account. Please wait...",
|
||||
"deleteAccountDescription": "This will delete your account and the accounts you own. Furthermore, we will immediately cancel any active subscriptions. This action cannot be undone.",
|
||||
"deleteProfileConfirmationInputLabel": "Type DELETE to confirm",
|
||||
"deleteAccountErrorHeading": "Sorry, we couldn't delete your account",
|
||||
"needsReauthentication": "Reauthentication Required",
|
||||
"needsReauthenticationDescription": "You need to reauthenticate to change your password. Please sign out and sign in again to change your password.",
|
||||
"language": "Language",
|
||||
"languageDescription": "Choose your preferred language",
|
||||
"noTeamsYet": "You don't have any teams yet.",
|
||||
"createTeam": "Create a team to get started.",
|
||||
"createTeamButtonLabel": "Create a Team",
|
||||
"createCompanyAccount": "Create Company Account",
|
||||
"requestCompanyAccount": "Request Company Account"
|
||||
}
|
||||
90
public/locales/ru/auth.json
Normal file
90
public/locales/ru/auth.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"signUpHeading": "Create an account",
|
||||
"signUp": "Sign Up",
|
||||
"signUpSubheading": "Fill the form below to create an account.",
|
||||
"signInHeading": "Sign in to your account",
|
||||
"signInSubheading": "Welcome back! Please enter your details",
|
||||
"signIn": "Sign In",
|
||||
"getStarted": "Get started",
|
||||
"updatePassword": "Update Password",
|
||||
"signOut": "Sign out",
|
||||
"signingIn": "Signing in...",
|
||||
"signingUp": "Signing up...",
|
||||
"doNotHaveAccountYet": "Do not have an account yet?",
|
||||
"alreadyHaveAnAccount": "Already have an account?",
|
||||
"signUpToAcceptInvite": "Please sign in/up to accept the invite",
|
||||
"clickToAcceptAs": "Click the button below to accept the invite with as <b>{{email}}</b>",
|
||||
"acceptInvite": "Accept invite",
|
||||
"acceptingInvite": "Accepting Invite...",
|
||||
"acceptInviteSuccess": "Invite successfully accepted",
|
||||
"acceptInviteError": "Error encountered while accepting invite",
|
||||
"acceptInviteWithDifferentAccount": "Want to accept the invite with a different account?",
|
||||
"alreadyHaveAccountStatement": "I already have an account, I want to sign in instead",
|
||||
"doNotHaveAccountStatement": "I do not have an account, I want to sign up instead",
|
||||
"signInWithProvider": "Sign in with {{provider}}",
|
||||
"signInWithPhoneNumber": "Sign in with Phone Number",
|
||||
"signInWithEmail": "Sign in with Email",
|
||||
"signUpWithEmail": "Sign up with Email",
|
||||
"passwordHint": "Ensure it's at least 8 characters",
|
||||
"repeatPasswordHint": "Type your password again",
|
||||
"repeatPassword": "Repeat password",
|
||||
"passwordForgottenQuestion": "Password forgotten?",
|
||||
"passwordResetLabel": "Reset Password",
|
||||
"passwordResetSubheading": "Enter your email address below. You will receive a link to reset your password.",
|
||||
"passwordResetSuccessMessage": "Check your Inbox! We emailed you a link for resetting your Password.",
|
||||
"passwordRecoveredQuestion": "Password recovered?",
|
||||
"passwordLengthError": "Please provide a password with at least 6 characters",
|
||||
"sendEmailLink": "Send Email Link",
|
||||
"sendingEmailLink": "Sending Email Link...",
|
||||
"sendLinkSuccessDescription": "Check your email, we just sent you a link. Follow the link to sign in.",
|
||||
"sendLinkSuccess": "We sent you a link by email",
|
||||
"sendLinkSuccessToast": "Link successfully sent",
|
||||
"getNewLink": "Get a new link",
|
||||
"verifyCodeHeading": "Verify your account",
|
||||
"verificationCode": "Verification Code",
|
||||
"verificationCodeHint": "Enter the code we sent you by SMS",
|
||||
"verificationCodeSubmitButtonLabel": "Submit Verification Code",
|
||||
"sendingMfaCode": "Sending Verification Code...",
|
||||
"verifyingMfaCode": "Verifying code...",
|
||||
"sendMfaCodeError": "Sorry, we couldn't send you a verification code",
|
||||
"verifyMfaCodeSuccess": "Code verified! Signing you in...",
|
||||
"verifyMfaCodeError": "Ops! It looks like the code is not correct",
|
||||
"reauthenticate": "Reauthenticate",
|
||||
"reauthenticateDescription": "For security reasons, we need you to re-authenticate",
|
||||
"errorAlertHeading": "Sorry, we could not authenticate you",
|
||||
"emailConfirmationAlertHeading": "We sent you a confirmation email.",
|
||||
"emailConfirmationAlertBody": "Welcome! Please check your email and click the link to verify your account.",
|
||||
"resendLink": "Resend link",
|
||||
"resendLinkSuccessDescription": "We sent you a new link to your email! Follow the link to sign in.",
|
||||
"resendLinkSuccess": "Check your email!",
|
||||
"authenticationErrorAlertHeading": "Authentication Error",
|
||||
"authenticationErrorAlertBody": "Sorry, we could not authenticate you. Please try again.",
|
||||
"sendEmailCode": "Get code to your Email",
|
||||
"sendingEmailCode": "Sending code...",
|
||||
"resetPasswordError": "Sorry, we could not reset your password. Please try again.",
|
||||
"emailPlaceholder": "your@email.com",
|
||||
"inviteAlertHeading": "You have been invited to join a team",
|
||||
"inviteAlertBody": "Please sign in or sign up to accept the invite and join the team.",
|
||||
"acceptTermsAndConditions": "I accept the <TermsOfServiceLink /> and <PrivacyPolicyLink />",
|
||||
"termsOfService": "Terms of Service",
|
||||
"privacyPolicy": "Privacy Policy",
|
||||
"orContinueWith": "Or continue with",
|
||||
"redirecting": "You're in! Please wait...",
|
||||
"errors": {
|
||||
"Invalid login credentials": "The credentials entered are invalid",
|
||||
"User already registered": "This credential is already in use. Please try with another one.",
|
||||
"Email not confirmed": "Please confirm your email address before signing in",
|
||||
"default": "We have encountered an error. Please ensure you have a working internet connection and try again",
|
||||
"generic": "Sorry, we weren't able to authenticate you. Please try again.",
|
||||
"link": "Sorry, we encountered an error while sending your link. Please try again.",
|
||||
"codeVerifierMismatch": "It looks like you're trying to sign in using a different browser than the one you used to request the sign in link. Please try again using the same browser.",
|
||||
"minPasswordLength": "Password must be at least 8 characters long",
|
||||
"passwordsDoNotMatch": "The passwords do not match",
|
||||
"minPasswordNumbers": "Password must contain at least one number",
|
||||
"minPasswordSpecialChars": "Password must contain at least one special character",
|
||||
"uppercasePassword": "Password must contain at least one uppercase letter",
|
||||
"insufficient_aal": "Please sign-in with your current multi-factor authentication to perform this action",
|
||||
"otp_expired": "The email link has expired. Please try again.",
|
||||
"same_password": "The password cannot be the same as the current password"
|
||||
}
|
||||
}
|
||||
120
public/locales/ru/billing.json
Normal file
120
public/locales/ru/billing.json
Normal file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"subscriptionTabSubheading": "Manage your Subscription and Billing",
|
||||
"planCardTitle": "Your Plan",
|
||||
"planCardDescription": "Below are the details of your current plan. You can change your plan or cancel your subscription at any time.",
|
||||
"planRenewal": "Renews every {{interval}} at {{price}}",
|
||||
"planDetails": "Plan Details",
|
||||
"checkout": "Proceed to Checkout",
|
||||
"trialEndsOn": "Your trial ends on",
|
||||
"billingPortalCardButton": "Visit Billing Portal",
|
||||
"billingPortalCardTitle": "Manage your Billing Details",
|
||||
"billingPortalCardDescription": "Visit your Billing Portal to manage your subscription and billing. You can update or cancel your plan, or download your invoices.",
|
||||
"cancelAtPeriodEndDescription": "Your subscription is scheduled to be canceled on {{- endDate }}.",
|
||||
"renewAtPeriodEndDescription": "Your subscription is scheduled to be renewed on {{- endDate }}",
|
||||
"noPermissionsAlertHeading": "You don't have permissions to change the billing settings",
|
||||
"noPermissionsAlertBody": "Please contact your account owner to change the billing settings for your account.",
|
||||
"checkoutSuccessTitle": "Done! You're all set.",
|
||||
"checkoutSuccessDescription": "Thank you for subscribing, we have successfully processed your subscription! A confirmation email will be sent to {{ customerEmail }}.",
|
||||
"checkoutSuccessBackButton": "Proceed to App",
|
||||
"cannotManageBillingAlertTitle": "You cannot manage billing",
|
||||
"cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account owner.",
|
||||
"manageTeamPlan": "Manage your Team Plan",
|
||||
"manageTeamPlanDescription": "Choose a plan that fits your team's needs. You can upgrade or downgrade your plan at any time.",
|
||||
"basePlan": "Base Plan",
|
||||
"billingInterval": {
|
||||
"label": "Choose your billing interval",
|
||||
"month": "Billed monthly",
|
||||
"year": "Billed yearly"
|
||||
},
|
||||
"perMonth": "month",
|
||||
"custom": "Custom Plan",
|
||||
"lifetime": "Lifetime",
|
||||
"trialPeriod": "{{period}} day trial",
|
||||
"perPeriod": "per {{period}}",
|
||||
"redirectingToPayment": "Redirecting to checkout. Please wait...",
|
||||
"proceedToPayment": "Proceed to Payment",
|
||||
"startTrial": "Start Trial",
|
||||
"perTeamMember": "Per team member",
|
||||
"perUnit": "Per {{unit}} usage",
|
||||
"teamMembers": "Team Members",
|
||||
"includedUpTo": "Up to {{upTo}} {{unit}} included in the plan",
|
||||
"fromPreviousTierUpTo": "for each {{unit}} for the next {{ upTo }} {{ unit }}",
|
||||
"andAbove": "above {{ previousTier }} {{ unit }}",
|
||||
"startingAtPriceUnit": "Starting at {{price}}/{{unit}}",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"forEveryUnit": "for every {{ unit }}",
|
||||
"setupFee": "plus a {{ setupFee }} setup fee",
|
||||
"perUnitIncluded": "({{included}} included)",
|
||||
"featuresLabel": "Features",
|
||||
"detailsLabel": "Details",
|
||||
"planPickerLabel": "Pick your preferred plan",
|
||||
"planCardLabel": "Manage your Plan",
|
||||
"planPickerAlertErrorTitle": "Error requesting checkout",
|
||||
"planPickerAlertErrorDescription": "There was an error requesting checkout. Please try again later.",
|
||||
"subscriptionCancelled": "Subscription Cancelled",
|
||||
"cancelSubscriptionDate": "Your subscription will be cancelled at the end of the period",
|
||||
"noPlanChosen": "Please choose a plan",
|
||||
"noIntervalPlanChosen": "Please choose a billing interval",
|
||||
"status": {
|
||||
"free": {
|
||||
"badge": "Free Plan",
|
||||
"heading": "You are currently on the Free Plan",
|
||||
"description": "You're on a free plan. You can upgrade to a paid plan at any time."
|
||||
},
|
||||
"active": {
|
||||
"badge": "Active",
|
||||
"heading": "Your subscription is active",
|
||||
"description": "Your subscription is active. You can manage your subscription and billing in the Customer Portal."
|
||||
},
|
||||
"trialing": {
|
||||
"badge": "Trial",
|
||||
"heading": "You're on a trial",
|
||||
"description": "You can enjoy the benefits of plan until the trial ends"
|
||||
},
|
||||
"past_due": {
|
||||
"badge": "Past Due",
|
||||
"heading": "Your invoice is past due",
|
||||
"description": "Your invoice is past due. Please update your payment method."
|
||||
},
|
||||
"canceled": {
|
||||
"badge": "Canceled",
|
||||
"heading": "Your subscription is canceled",
|
||||
"description": "Your subscription is canceled. It is scheduled to end at end of the billing period."
|
||||
},
|
||||
"unpaid": {
|
||||
"badge": "Unpaid",
|
||||
"heading": "Your invoice is unpaid",
|
||||
"description": "Your invoice is unpaid. Please update your payment method."
|
||||
},
|
||||
"incomplete": {
|
||||
"badge": "Incomplete",
|
||||
"heading": "We're waiting for your payment",
|
||||
"description": "We're waiting for your payment to go through. Please bear with us."
|
||||
},
|
||||
"incomplete_expired": {
|
||||
"badge": "Expired",
|
||||
"heading": "Your payment has expired",
|
||||
"description": "Your payment has expired. Please update your payment method."
|
||||
},
|
||||
"paused": {
|
||||
"badge": "Paused",
|
||||
"heading": "Your subscription is paused",
|
||||
"description": "Your subscription is paused. You can resume it at any time."
|
||||
},
|
||||
"succeeded": {
|
||||
"badge": "Succeeded",
|
||||
"heading": "Your payment was successful",
|
||||
"description": "Your payment was successful. Thank you for subscribing!"
|
||||
},
|
||||
"pending": {
|
||||
"badge": "Pending",
|
||||
"heading": "Your payment is pending",
|
||||
"description": "Your payment is pending. Please bear with us."
|
||||
},
|
||||
"failed": {
|
||||
"badge": "Failed",
|
||||
"heading": "Your payment failed",
|
||||
"description": "Your payment failed. Please update your payment method."
|
||||
}
|
||||
}
|
||||
}
|
||||
96
public/locales/ru/common.json
Normal file
96
public/locales/ru/common.json
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"homeTabLabel": "Home",
|
||||
"homeTabDescription": "Welcome to your home page",
|
||||
"accountMembers": "Team Members",
|
||||
"membersTabDescription": "Here you can manage the members of your team.",
|
||||
"billingTabLabel": "Billing",
|
||||
"billingTabDescription": "Manage your billing and subscription",
|
||||
"dashboardTabLabel": "Dashboard",
|
||||
"settingsTabLabel": "Settings",
|
||||
"profileSettingsTabLabel": "Profile",
|
||||
"subscriptionSettingsTabLabel": "Subscription",
|
||||
"dashboardTabDescription": "An overview of your account's activity and performance across all your projects.",
|
||||
"settingsTabDescription": "Manage your settings and preferences.",
|
||||
"emailAddress": "Email Address",
|
||||
"password": "Password",
|
||||
"modalConfirmationQuestion": "Are you sure you want to continue?",
|
||||
"imageInputLabel": "Click here to upload an image",
|
||||
"cancel": "Cancel",
|
||||
"clear": "Clear",
|
||||
"notFound": "Not Found",
|
||||
"backToHomePage": "Back to Home Page",
|
||||
"goBack": "Go Back",
|
||||
"genericServerError": "Sorry, something went wrong.",
|
||||
"genericServerErrorHeading": "Sorry, something went wrong while processing your request. Please contact us if the issue persists.",
|
||||
"pageNotFound": "Sorry, this page does not exist.",
|
||||
"pageNotFoundSubHeading": "Apologies, the page you were looking for was not found",
|
||||
"genericError": "Sorry, something went wrong.",
|
||||
"genericErrorSubHeading": "Apologies, an error occurred while processing your request. Please contact us if the issue persists.",
|
||||
"anonymousUser": "Anonymous",
|
||||
"tryAgain": "Try Again",
|
||||
"theme": "Theme",
|
||||
"lightTheme": "Light",
|
||||
"darkTheme": "Dark",
|
||||
"systemTheme": "System",
|
||||
"expandSidebar": "Expand Sidebar",
|
||||
"collapseSidebar": "Collapse Sidebar",
|
||||
"documentation": "Documentation",
|
||||
"getStarted": "Get Started",
|
||||
"getStartedWithPlan": "Get Started with {{plan}}",
|
||||
"retry": "Retry",
|
||||
"contactUs": "Contact Us",
|
||||
"loading": "Loading. Please wait...",
|
||||
"yourAccounts": "Your Accounts",
|
||||
"continue": "Continue",
|
||||
"skip": "Skip",
|
||||
"signedInAs": "Signed in as",
|
||||
"pageOfPages": "Page {{page}} of {{total}}",
|
||||
"noData": "No data available",
|
||||
"pageNotFoundHeading": "Ouch! :|",
|
||||
"errorPageHeading": "Ouch! :|",
|
||||
"notifications": "Notifications",
|
||||
"noNotifications": "No notifications",
|
||||
"justNow": "Just now",
|
||||
"newVersionAvailable": "New version available",
|
||||
"newVersionAvailableDescription": "A new version of the app is available. It is recommended to refresh the page to get the latest updates and avoid any issues.",
|
||||
"newVersionSubmitButton": "Reload and Update",
|
||||
"back": "Back",
|
||||
"routes": {
|
||||
"home": "Home",
|
||||
"account": "Account",
|
||||
"members": "Members",
|
||||
"billing": "Billing",
|
||||
"dashboard": "Dashboard",
|
||||
"settings": "Settings",
|
||||
"profile": "Profile",
|
||||
"application": "Application"
|
||||
},
|
||||
"roles": {
|
||||
"owner": {
|
||||
"label": "Owner"
|
||||
},
|
||||
"member": {
|
||||
"label": "Member"
|
||||
}
|
||||
},
|
||||
"otp": {
|
||||
"requestVerificationCode": "Request Verification Code",
|
||||
"requestVerificationCodeDescription": "We must verify your identity to continue with this action. We'll send a verification code to the email address {{email}}.",
|
||||
"sendingCode": "Sending Code...",
|
||||
"sendVerificationCode": "Send Verification Code",
|
||||
"enterVerificationCode": "Enter Verification Code",
|
||||
"codeSentToEmail": "We've sent a verification code to the email address {{email}}.",
|
||||
"verificationCode": "Verification Code",
|
||||
"enterCodeFromEmail": "Enter the 6-digit code we sent to your email.",
|
||||
"verifying": "Verifying...",
|
||||
"verifyCode": "Verify Code",
|
||||
"requestNewCode": "Request New Code",
|
||||
"errorSendingCode": "Error sending code. Please try again."
|
||||
},
|
||||
"cookieBanner": {
|
||||
"title": "Hey, we use cookies 🍪",
|
||||
"description": "This website uses cookies to ensure you get the best experience on our website.",
|
||||
"reject": "Reject",
|
||||
"accept": "Accept"
|
||||
}
|
||||
}
|
||||
40
public/locales/ru/marketing.json
Normal file
40
public/locales/ru/marketing.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"blog": "Blog",
|
||||
"blogSubtitle": "News and updates about the platform",
|
||||
"documentation": "Documentation",
|
||||
"documentationSubtitle": "Tutorials and guide to get started with the platform",
|
||||
"faq": "FAQ",
|
||||
"faqSubtitle": "Frequently asked questions about the platform",
|
||||
"pricing": "Pricing",
|
||||
"pricingSubtitle": "Pricing plans and payment options",
|
||||
"backToBlog": "Back to blog",
|
||||
"noPosts": "No posts found",
|
||||
"blogPaginationNext": "Next Page",
|
||||
"blogPaginationPrevious": "Previous Page",
|
||||
"readMore": "Read more",
|
||||
"contactFaq": "If you have any questions, please contact us",
|
||||
"contact": "Contact",
|
||||
"about": "About",
|
||||
"product": "Product",
|
||||
"legal": "Legal",
|
||||
"termsOfService": "Terms of Service",
|
||||
"termsOfServiceDescription": "Our terms and conditions",
|
||||
"cookiePolicy": "Cookie Policy",
|
||||
"cookiePolicyDescription": "Our cookie policy and how we use them",
|
||||
"privacyPolicy": "Privacy Policy",
|
||||
"privacyPolicyDescription": "Our privacy policy and how we use your data",
|
||||
"contactDescription": "Contact us for any questions or feedback",
|
||||
"contactHeading": "Send us a message",
|
||||
"contactSubheading": "We will get back to you as soon as possible",
|
||||
"contactName": "Your Name",
|
||||
"contactEmail": "Your Email",
|
||||
"contactMessage": "Your Message",
|
||||
"sendMessage": "Send Message",
|
||||
"contactSuccess": "Your message has been sent successfully",
|
||||
"contactError": "An error occurred while sending your message",
|
||||
"contactSuccessDescription": "We have received your message and will get back to you as soon as possible",
|
||||
"contactErrorDescription": "An error occurred while sending your message. Please try again later",
|
||||
"footerDescription": "Here you can add a description about your company or product",
|
||||
"copyright": "© Copyright {{year}} {{product}}. All Rights Reserved.",
|
||||
"heroSubtitle": "Простой, удобный и быстрый обзор вашего состояния здоровья"
|
||||
}
|
||||
163
public/locales/ru/teams.json
Normal file
163
public/locales/ru/teams.json
Normal file
@@ -0,0 +1,163 @@
|
||||
{
|
||||
"home": {
|
||||
"pageTitle": "Home"
|
||||
},
|
||||
"settings": {
|
||||
"pageTitle": "Settings",
|
||||
"pageDescription": "Manage your Team details",
|
||||
"teamLogo": "Team Logo",
|
||||
"teamLogoDescription": "Update your team's logo to make it easier to identify",
|
||||
"teamName": "Team Name",
|
||||
"teamNameDescription": "Update your team's name",
|
||||
"dangerZone": "Danger Zone",
|
||||
"dangerZoneDescription": "This section contains actions that are irreversible"
|
||||
},
|
||||
"members": {
|
||||
"pageTitle": "Members"
|
||||
},
|
||||
"billing": {
|
||||
"pageTitle": "Billing"
|
||||
},
|
||||
"yourTeams": "Your Teams ({{teamsCount}})",
|
||||
"createTeam": "Create a Team",
|
||||
"creatingTeam": "Creating Team...",
|
||||
"personalAccount": "Personal Account",
|
||||
"searchAccount": "Search Account...",
|
||||
"membersTabLabel": "Members",
|
||||
"memberName": "Name",
|
||||
"youLabel": "You",
|
||||
"emailLabel": "Email",
|
||||
"roleLabel": "Role",
|
||||
"primaryOwnerLabel": "Primary Owner",
|
||||
"joinedAtLabel": "Joined at",
|
||||
"invitedAtLabel": "Invited at",
|
||||
"inviteMembersPageSubheading": "Invite members to your Team",
|
||||
"createTeamModalHeading": "Create Team",
|
||||
"createTeamModalDescription": "Create a new Team to manage your projects and members.",
|
||||
"teamNameLabel": "Team Name",
|
||||
"teamNameDescription": "Your team name should be unique and descriptive",
|
||||
"createTeamSubmitLabel": "Create Team",
|
||||
"createTeamSuccess": "Team created successfully",
|
||||
"createTeamError": "Team not created. Please try again.",
|
||||
"createTeamLoading": "Creating team...",
|
||||
"settingsPageLabel": "General",
|
||||
"createTeamDropdownLabel": "New team",
|
||||
"changeRole": "Change Role",
|
||||
"removeMember": "Remove from Account",
|
||||
"inviteMembersSuccess": "Members invited successfully!",
|
||||
"inviteMembersError": "Sorry, we encountered an error! Please try again",
|
||||
"inviteMembersLoading": "Inviting members...",
|
||||
"removeInviteButtonLabel": "Remove invite",
|
||||
"addAnotherMemberButtonLabel": "Add another one",
|
||||
"inviteMembersButtonLabel": "Send Invites",
|
||||
"removeMemberModalHeading": "You are removing this user",
|
||||
"removeMemberModalDescription": "Remove this member from the team. They will no longer have access to the team.",
|
||||
"removeMemberSuccessMessage": "Member removed successfully",
|
||||
"removeMemberErrorMessage": "Sorry, we encountered an error. Please try again",
|
||||
"removeMemberErrorHeading": "Sorry, we couldn't remove the selected member.",
|
||||
"removeMemberLoadingMessage": "Removing member...",
|
||||
"removeMemberSubmitLabel": "Remove User from Team",
|
||||
"chooseDifferentRoleError": "Role is the same as the current one",
|
||||
"updateRole": "Update Role",
|
||||
"updateRoleLoadingMessage": "Updating role...",
|
||||
"updateRoleSuccessMessage": "Role updated successfully",
|
||||
"updatingRoleErrorMessage": "Sorry, we encountered an error. Please try again.",
|
||||
"updateMemberRoleModalHeading": "Update Member's Role",
|
||||
"updateMemberRoleModalDescription": "Change the role of the selected member. The role determines the permissions of the member.",
|
||||
"roleMustBeDifferent": "Role must be different from the current one",
|
||||
"memberRoleInputLabel": "Member role",
|
||||
"updateRoleDescription": "Pick a role for this member.",
|
||||
"updateRoleSubmitLabel": "Update Role",
|
||||
"transferOwnership": "Transfer Ownership",
|
||||
"transferOwnershipDescription": "Transfer ownership of the team to another member.",
|
||||
"transferOwnershipInputLabel": "Please type TRANSFER to confirm the transfer of ownership.",
|
||||
"transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the team.",
|
||||
"deleteInvitation": "Delete Invitation",
|
||||
"deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the team.",
|
||||
"deleteInviteSuccessMessage": "Invite deleted successfully",
|
||||
"deleteInviteErrorMessage": "Invite not deleted. Please try again.",
|
||||
"deleteInviteLoadingMessage": "Deleting invite. Please wait...",
|
||||
"confirmDeletingMemberInvite": "You are deleting the invite to <b>{{ email }}</b>",
|
||||
"transferOwnershipDisclaimer": "You are transferring ownership of the selected team to <b>{{ member }}</b>.",
|
||||
"transferringOwnership": "Transferring ownership...",
|
||||
"transferOwnershipSuccess": "Ownership successfully transferred",
|
||||
"transferOwnershipError": "Sorry, we could not transfer ownership to the selected member. Please try again.",
|
||||
"deleteInviteSubmitLabel": "Delete Invite",
|
||||
"youBadgeLabel": "You",
|
||||
"updateTeamLoadingMessage": "Updating Team...",
|
||||
"updateTeamSuccessMessage": "Team successfully updated",
|
||||
"updateTeamErrorMessage": "Could not update Team. Please try again.",
|
||||
"updateLogoErrorMessage": "Could not update Logo. Please try again.",
|
||||
"teamNameInputLabel": "Team Name",
|
||||
"teamLogoInputHeading": "Upload your team's Logo",
|
||||
"teamLogoInputSubheading": "Please choose a photo to upload as your team logo.",
|
||||
"updateTeamSubmitLabel": "Update Team",
|
||||
"inviteMembersHeading": "Invite Members to your Team",
|
||||
"inviteMembersDescription": "Invite members to your team by entering their email and role.",
|
||||
"emailPlaceholder": "member@email.com",
|
||||
"membersPageHeading": "Members",
|
||||
"inviteMembersButton": "Invite Members",
|
||||
"invitingMembers": "Inviting members...",
|
||||
"inviteMembersSuccessMessage": "Members invited successfully",
|
||||
"inviteMembersErrorMessage": "Sorry, members could not be invited. Please try again.",
|
||||
"pendingInvitesHeading": "Pending Invites",
|
||||
"pendingInvitesDescription": " Here you can manage the pending invitations to your team.",
|
||||
"noPendingInvites": "No pending invites found",
|
||||
"loadingMembers": "Loading members...",
|
||||
"loadMembersError": "Sorry, we couldn't fetch your team's members.",
|
||||
"loadInvitedMembersError": "Sorry, we couldn't fetch your team's invited members.",
|
||||
"loadingInvitedMembers": "Loading invited members...",
|
||||
"invitedBadge": "Invited",
|
||||
"duplicateInviteEmailError": "You have already entered this email address",
|
||||
"invitingOwnAccountError": "Hey, that's your email!",
|
||||
"dangerZone": "Danger Zone",
|
||||
"dangerZoneSubheading": "Delete or leave your team",
|
||||
"deleteTeam": "Delete Team",
|
||||
"deleteTeamDescription": "This action cannot be undone. All data associated with this team will be deleted.",
|
||||
"deletingTeam": "Deleting team",
|
||||
"deleteTeamModalHeading": "Deleting Team",
|
||||
"deletingTeamDescription": "You are about to delete the team {{ teamName }}. This action cannot be undone.",
|
||||
"deleteTeamInputField": "Type the name of the team to confirm",
|
||||
"leaveTeam": "Leave Team",
|
||||
"leavingTeamModalHeading": "Leaving Team",
|
||||
"leavingTeamModalDescription": "You are about to leave this team. You will no longer have access to it.",
|
||||
"leaveTeamDescription": "Click the button below to leave the team. Remember, you will no longer have access to it and will need to be re-invited to join.",
|
||||
"deleteTeamDisclaimer": "You are deleting the team {{ teamName }}. This action cannot be undone.",
|
||||
"leaveTeamDisclaimer": "You are leaving the team {{ teamName }}. You will no longer have access to it.",
|
||||
"deleteTeamErrorHeading": "Sorry, we couldn't delete your team.",
|
||||
"leaveTeamErrorHeading": "Sorry, we couldn't leave your team.",
|
||||
"searchMembersPlaceholder": "Search members",
|
||||
"createTeamErrorHeading": "Sorry, we couldn't create your team.",
|
||||
"createTeamErrorMessage": "We encountered an error creating your team. Please try again.",
|
||||
"transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your team.",
|
||||
"transferTeamErrorMessage": "We encountered an error transferring ownership of your team. Please try again.",
|
||||
"updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected member.",
|
||||
"updateRoleErrorMessage": "We encountered an error updating the role of the selected member. Please try again.",
|
||||
"searchInvitations": "Search Invitations",
|
||||
"updateInvitation": "Update Invitation",
|
||||
"removeInvitation": "Remove Invitation",
|
||||
"acceptInvitation": "Accept Invitation",
|
||||
"renewInvitation": "Renew Invitation",
|
||||
"resendInvitation": "Resend Invitation",
|
||||
"expiresAtLabel": "Expires at",
|
||||
"expired": "Expired",
|
||||
"active": "Active",
|
||||
"inviteStatus": "Status",
|
||||
"inviteNotFoundOrExpired": "Invite not found or expired",
|
||||
"inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the team owner to renew the invite.",
|
||||
"backToHome": "Back to Home",
|
||||
"renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the team.",
|
||||
"renewInvitationErrorTitle": "Sorry, we couldn't renew the invitation.",
|
||||
"renewInvitationErrorDescription": "We encountered an error renewing the invitation. Please try again.",
|
||||
"signInWithDifferentAccount": "Sign in with a different account",
|
||||
"signInWithDifferentAccountDescription": "If you wish to accept the invitation with a different account, please sign out and back in with the account you wish to use.",
|
||||
"acceptInvitationHeading": "Accept Invitation to join {{accountName}}",
|
||||
"acceptInvitationDescription": "You have been invited to join the team {{accountName}}. If you wish to accept the invitation, please click the button below.",
|
||||
"continueAs": "Continue as {{email}}",
|
||||
"joinTeamAccount": "Join Team",
|
||||
"joiningTeam": "Joining team...",
|
||||
"leaveTeamInputLabel": "Please type LEAVE to confirm leaving the team.",
|
||||
"leaveTeamInputDescription": "By leaving the team, you will no longer have access to it.",
|
||||
"reservedNameError": "This name is reserved. Please choose a different one.",
|
||||
"specialCharactersError": "This name cannot contain special characters. Please choose a different one."
|
||||
}
|
||||
@@ -32,6 +32,7 @@
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
font-feature-settings: "rlig" 1, "calt" 1;
|
||||
/* @apply font-sans */
|
||||
}
|
||||
|
||||
*,
|
||||
@@ -46,4 +47,10 @@
|
||||
textarea::placeholder {
|
||||
color: theme(--color-muted-foreground);
|
||||
}
|
||||
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
@apply font-heading text-foreground text-2xl font-semibold tracking-tight
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,38 +8,39 @@
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
--font-heading: var(--font-sans);
|
||||
|
||||
--font-sans: var(--font-sans) -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
--font-heading: var(--font-heading);
|
||||
|
||||
--background: var(--color-white);
|
||||
--foreground: var(--color-neutral-950);
|
||||
--foreground: hsla(240, 10%, 4%, 1);
|
||||
|
||||
--card: var(--color-white);
|
||||
--card-foreground: var(--color-neutral-950);
|
||||
|
||||
--popover: var(--color-white);
|
||||
--popover-foreground: var(--color-neutral-950);
|
||||
--popover-foreground: hsla(240, 10%, 4%, 1);
|
||||
|
||||
--primary: var(--color-neutral-950);
|
||||
--primary-foreground: var(--color-white);
|
||||
--primary: hsla(145, 78%, 18%, 1);
|
||||
--primary-foreground: hsla(356, 100%, 97%, 1);
|
||||
|
||||
--secondary: oklch(96.76% 0.0013 286.38);
|
||||
--secondary-foreground: oklch(21.03% 0.0318 264.65);
|
||||
--secondary: hsla(240, 5%, 96%, 1);
|
||||
--secondary-foreground: hsla(240, 6%, 10%, 1);
|
||||
|
||||
--muted: oklch(96.71% 0.0029 264.54);
|
||||
--muted-foreground: oklch(55.13% 0.0233 264.36);
|
||||
--muted: hsla(240, 5%, 96%, 1);
|
||||
--muted-foreground: hsla(240, 4%, 41%, 1);
|
||||
|
||||
--accent: oklch(96.76% 0.0013 286.38);
|
||||
--accent-foreground: oklch(21.03% 0.0318 264.65);
|
||||
--accent: hsla(240, 5%, 96%, 1);
|
||||
--accent-foreground: hsla(240, 6%, 10%, 1);
|
||||
|
||||
--destructive: var(--color-red-500);
|
||||
--destructive-foreground: var(--color-white);
|
||||
--destructive: hsla(0, 84%, 60%, 1);
|
||||
--destructive-foreground: hsla(0, 0%, 98%, 1);
|
||||
|
||||
--border: var(--color-gray-100);
|
||||
--input: var(--color-gray-200);
|
||||
--border: hsla(240, 6%, 90%, 1);
|
||||
--input: hsla(240, 6%, 90%, 1);
|
||||
--ring: var(--color-neutral-800);
|
||||
|
||||
--radius: 0.5rem;
|
||||
--radius: 1rem;
|
||||
|
||||
--chart-1: var(--color-orange-400);
|
||||
--chart-2: var(--color-teal-600);
|
||||
@@ -55,6 +56,7 @@
|
||||
--sidebar-accent-foreground: var(--color-neutral-950);
|
||||
--sidebar-border: var(--border);
|
||||
--sidebar-ring: var(--color-blue-500);
|
||||
/* --foreground: 240 10% 4%; */
|
||||
}
|
||||
|
||||
.dark {
|
||||
@@ -74,7 +76,7 @@
|
||||
--secondary-foreground: oklch(98.43% 0.0017 247.84);
|
||||
|
||||
--muted: var(--color-neutral-800);
|
||||
--muted-foreground: oklch(71.19% 0.0129 286.07);
|
||||
--muted-foreground: hsla(240, 4%, 41%, 1);
|
||||
|
||||
--accent: var(--color-neutral-800);
|
||||
--accent-foreground: oklch(98.48% 0 0);
|
||||
|
||||
@@ -66,6 +66,16 @@
|
||||
--animate-accordion-down: accordion-down 0.2s ease-out;
|
||||
--animate-accordion-up: accordion-up 0.2s ease-out;
|
||||
|
||||
--breakpoint-xs: 30rem;
|
||||
--breakpoint-sm: 48rem;
|
||||
--breakpoint-md: 70rem;
|
||||
--breakpoint-lg: 80rem;
|
||||
--breakpoint-xl: 96rem;
|
||||
--breakpoint-2xl: 100rem;
|
||||
--breakpoint-3xl: 120rem;
|
||||
|
||||
--container-max-width: 80rem;
|
||||
|
||||
@keyframes accordion-down {
|
||||
from {
|
||||
height: 0;
|
||||
|
||||
@@ -10,7 +10,7 @@ enabled = true
|
||||
port = 54321
|
||||
# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
|
||||
# endpoints. `public` and `graphql_public` schemas are included by default.
|
||||
schemas = ["public", "graphql_public"]
|
||||
schemas = ["public", "graphql_public", "audit"]
|
||||
# Extra schemas to add to the search_path of every request.
|
||||
extra_search_path = ["public", "extensions"]
|
||||
# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
|
||||
|
||||
1285
supabase/database.types.ts
Normal file
1285
supabase/database.types.ts
Normal file
File diff suppressed because it is too large
Load Diff
206
supabase/migrations/20250602164242_create_medipost_tables.sql
Normal file
206
supabase/migrations/20250602164242_create_medipost_tables.sql
Normal file
@@ -0,0 +1,206 @@
|
||||
create table "public"."analyses" (
|
||||
"id" bigint generated by default as identity not null,
|
||||
"analysis_id_oid" text not null,
|
||||
"analysis_id_original" text not null,
|
||||
"tehik_short_loinc" text,
|
||||
"tehik_loinc_name" text,
|
||||
"analysis_name_lab" text,
|
||||
"order" smallint,
|
||||
"created_at" timestamp with time zone not null default now(),
|
||||
"updated_at" timestamp with time zone default now(),
|
||||
"parent_analysis_element_id" bigint not null
|
||||
);
|
||||
|
||||
|
||||
alter table "public"."analyses" enable row level security;
|
||||
|
||||
create table "public"."analysis_elements" (
|
||||
"id" bigint generated by default as identity not null,
|
||||
"analysis_id_oid" text,
|
||||
"analysis_id_original" text not null,
|
||||
"tehik_short_loinc" text,
|
||||
"tehik_loinc_name" text,
|
||||
"analysis_name_lab" text,
|
||||
"order" smallint,
|
||||
"created_at" timestamp with time zone not null default now(),
|
||||
"updated_at" timestamp with time zone default now(),
|
||||
"parent_analysis_group_id" bigint not null,
|
||||
"material_groups" jsonb[]
|
||||
);
|
||||
|
||||
|
||||
alter table "public"."analysis_elements" enable row level security;
|
||||
|
||||
create table "public"."analysis_groups" (
|
||||
"id" bigint generated by default as identity not null,
|
||||
"original_id" text not null,
|
||||
"name" text,
|
||||
"order" smallint,
|
||||
"created_at" timestamp with time zone not null default now(),
|
||||
"updated_at" timestamp with time zone default now()
|
||||
);
|
||||
|
||||
|
||||
alter table "public"."analysis_groups" enable row level security;
|
||||
|
||||
create table "public"."codes" (
|
||||
"id" bigint generated by default as identity not null,
|
||||
"hk_code" text not null,
|
||||
"hk_code_multiplier" bigint not null,
|
||||
"coefficient" double precision not null,
|
||||
"price" double precision not null,
|
||||
"analysis_group_id" bigint,
|
||||
"analysis_element_id" bigint,
|
||||
"analysis_id" bigint,
|
||||
"updated_at" timestamp with time zone default now(),
|
||||
"created_at" timestamp with time zone not null default now()
|
||||
);
|
||||
|
||||
|
||||
alter table "public"."codes" enable row level security;
|
||||
|
||||
CREATE UNIQUE INDEX analysis_elements_pkey ON public.analysis_elements USING btree (id);
|
||||
|
||||
CREATE UNIQUE INDEX analysis_elements_original_id_key ON public.analysis_elements USING btree (analysis_id_original);
|
||||
|
||||
CREATE UNIQUE INDEX analysis_group_original_id_key ON public.analysis_groups USING btree (original_id);
|
||||
|
||||
CREATE UNIQUE INDEX analysis_group_pkey ON public.analysis_groups USING btree (id);
|
||||
|
||||
CREATE UNIQUE INDEX analysis_pkey ON public.analyses USING btree (id);
|
||||
|
||||
CREATE UNIQUE INDEX analysis_original_id_key ON public.analysis_elements USING btree (analysis_id_original);
|
||||
|
||||
CREATE UNIQUE INDEX codes_pkey ON public.codes USING btree (id);
|
||||
|
||||
CREATE UNIQUE INDEX analyses_analysis_id_original_key ON public.analyses USING btree (analysis_id_original);
|
||||
|
||||
CREATE UNIQUE INDEX analysis_elements_analysis_id_original_key ON public.analysis_elements USING btree (analysis_id_original);
|
||||
|
||||
alter table "public"."analyses" add constraint "analyses_analysis_id_original_key" UNIQUE using index "analyses_analysis_id_original_key";
|
||||
|
||||
alter table "public"."analysis_elements" add constraint "analysis_elements_analysis_id_original_key" UNIQUE using index "analysis_elements_analysis_id_original_key";
|
||||
|
||||
alter table "public"."analyses" add constraint "analysis_pkey" PRIMARY KEY using index "analysis_pkey";
|
||||
|
||||
alter table "public"."analysis_elements" add constraint "analysis_elements_pkey" PRIMARY KEY using index "analysis_elements_pkey";
|
||||
|
||||
alter table "public"."analysis_groups" add constraint "analysis_group_pkey" PRIMARY KEY using index "analysis_group_pkey";
|
||||
|
||||
alter table "public"."codes" add constraint "codes_pkey" PRIMARY KEY using index "codes_pkey";
|
||||
|
||||
alter table "public"."analyses" add constraint "analyses_parent_analysis_element_id_fkey" FOREIGN KEY (parent_analysis_element_id) REFERENCES analysis_elements(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
||||
|
||||
alter table "public"."analyses" validate constraint "analyses_parent_analysis_element_id_fkey";
|
||||
|
||||
alter table "public"."analysis_elements" add constraint "analysis_elements_parent_analysis_group_id_fkey" FOREIGN KEY (parent_analysis_group_id) REFERENCES analysis_groups(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
||||
|
||||
alter table "public"."analysis_elements" validate constraint "analysis_elements_parent_analysis_group_id_fkey";
|
||||
|
||||
alter table "public"."analysis_groups" add constraint "analysis_group_original_id_key" UNIQUE using index "analysis_group_original_id_key";
|
||||
|
||||
alter table "public"."codes" add constraint "codes_analysis_element_id_fkey" FOREIGN KEY (analysis_element_id) REFERENCES analysis_elements(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
||||
|
||||
alter table "public"."codes" validate constraint "codes_analysis_element_id_fkey";
|
||||
|
||||
alter table "public"."codes" add constraint "codes_analysis_group_id_fkey" FOREIGN KEY (analysis_group_id) REFERENCES analysis_groups(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
||||
|
||||
alter table "public"."codes" validate constraint "codes_analysis_group_id_fkey";
|
||||
|
||||
alter table "public"."codes" add constraint "codes_analysis_id_fkey" FOREIGN KEY (analysis_id) REFERENCES analyses(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
||||
|
||||
alter table "public"."codes" validate constraint "codes_analysis_id_fkey";
|
||||
|
||||
grant delete on table "public"."analyses" to "service_role";
|
||||
|
||||
grant insert on table "public"."analyses" to "service_role";
|
||||
|
||||
grant references on table "public"."analyses" to "service_role";
|
||||
|
||||
grant select on table "public"."analyses" to "service_role";
|
||||
|
||||
grant trigger on table "public"."analyses" to "service_role";
|
||||
|
||||
grant truncate on table "public"."analyses" to "service_role";
|
||||
|
||||
grant update on table "public"."analyses" to "service_role";
|
||||
|
||||
grant delete on table "public"."analysis_elements" to "service_role";
|
||||
|
||||
grant insert on table "public"."analysis_elements" to "service_role";
|
||||
|
||||
grant references on table "public"."analysis_elements" to "service_role";
|
||||
|
||||
grant select on table "public"."analysis_elements" to "service_role";
|
||||
|
||||
grant trigger on table "public"."analysis_elements" to "service_role";
|
||||
|
||||
grant truncate on table "public"."analysis_elements" to "service_role";
|
||||
|
||||
grant update on table "public"."analysis_elements" to "service_role";
|
||||
|
||||
grant delete on table "public"."analysis_groups" to "service_role";
|
||||
|
||||
grant insert on table "public"."analysis_groups" to "service_role";
|
||||
|
||||
grant references on table "public"."analysis_groups" to "service_role";
|
||||
|
||||
grant select on table "public"."analysis_groups" to "service_role";
|
||||
|
||||
grant trigger on table "public"."analysis_groups" to "service_role";
|
||||
|
||||
grant truncate on table "public"."analysis_groups" to "service_role";
|
||||
|
||||
grant update on table "public"."analysis_groups" to "service_role";
|
||||
|
||||
grant delete on table "public"."codes" to "service_role";
|
||||
|
||||
grant insert on table "public"."codes" to "service_role";
|
||||
|
||||
grant references on table "public"."codes" to "service_role";
|
||||
|
||||
grant select on table "public"."codes" to "service_role";
|
||||
|
||||
grant trigger on table "public"."codes" to "service_role";
|
||||
|
||||
grant truncate on table "public"."codes" to "service_role";
|
||||
|
||||
grant update on table "public"."codes" to "service_role";
|
||||
|
||||
create policy "analysis_all"
|
||||
on "public"."analyses"
|
||||
as permissive
|
||||
for all
|
||||
to service_role
|
||||
using (true);
|
||||
|
||||
|
||||
create policy "analysis_elements_all"
|
||||
on "public"."analysis_elements"
|
||||
as permissive
|
||||
for all
|
||||
to service_role
|
||||
using (true);
|
||||
|
||||
|
||||
create policy "analysis_groups_all"
|
||||
on "public"."analysis_groups"
|
||||
as permissive
|
||||
for all
|
||||
to service_role
|
||||
using (true);
|
||||
|
||||
|
||||
create policy "codes_all"
|
||||
on "public"."codes"
|
||||
as permissive
|
||||
for all
|
||||
to service_role
|
||||
using (true);
|
||||
|
||||
|
||||
CREATE TRIGGER analysis_change_record_timestamps AFTER INSERT OR DELETE OR UPDATE ON public.analyses FOR EACH ROW EXECUTE FUNCTION trigger_set_timestamps();
|
||||
CREATE TRIGGER analysis_elements_change_record_timestamps AFTER INSERT OR DELETE OR UPDATE ON public.analysis_elements FOR EACH ROW EXECUTE FUNCTION trigger_set_timestamps();
|
||||
CREATE TRIGGER analysis_groups_change_record_timestamps AFTER INSERT OR DELETE OR UPDATE ON public.analysis_groups FOR EACH ROW EXECUTE FUNCTION trigger_set_timestamps();
|
||||
CREATE TRIGGER codes_change_record_timestamps AFTER INSERT OR DELETE OR UPDATE ON public.codes FOR EACH ROW EXECUTE FUNCTION trigger_set_timestamps();
|
||||
|
||||
87
supabase/migrations/20250604115051_add_audit_schema.sql
Normal file
87
supabase/migrations/20250604115051_add_audit_schema.sql
Normal file
@@ -0,0 +1,87 @@
|
||||
create schema if not exists audit;
|
||||
|
||||
create table if not exists audit.log_entries (
|
||||
"id" bigint generated by default as identity not null,
|
||||
"schema_name" text not null,
|
||||
"table_name" text not null,
|
||||
"record_key" bigint,
|
||||
"operation" text not null,
|
||||
"row_data" jsonb,
|
||||
"changed_data" jsonb,
|
||||
"changed_by" uuid,
|
||||
"changed_by_role" text,
|
||||
"changed_at" timestamptz not null default now()
|
||||
);
|
||||
|
||||
alter table "audit"."log_entries" enable row level security;
|
||||
|
||||
create policy "service_role_all"
|
||||
on "audit"."log_entries"
|
||||
as permissive
|
||||
for all
|
||||
to service_role
|
||||
using (true);
|
||||
|
||||
create or replace function audit.log_audit_changes()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
as $$
|
||||
declare
|
||||
current_user_id uuid;
|
||||
current_user_role text;
|
||||
begin
|
||||
begin
|
||||
current_user_id := auth.uid();
|
||||
current_user_role := auth.jwt() ->> 'role';
|
||||
end;
|
||||
|
||||
insert into audit.log_entries (
|
||||
schema_name,
|
||||
table_name,
|
||||
record_key,
|
||||
operation,
|
||||
row_data,
|
||||
changed_data,
|
||||
changed_by,
|
||||
changed_by_role
|
||||
)
|
||||
values (
|
||||
tg_table_schema,
|
||||
tg_table_name,
|
||||
case when tg_op in ('DELETE', 'UPDATE') then old.id else null end,
|
||||
tg_op,
|
||||
case when tg_op in ('DELETE', 'UPDATE') then to_jsonb(old) else null end,
|
||||
case when tg_op in ('INSERT', 'UPDATE') then to_jsonb(new) else null end,
|
||||
current_user_id,
|
||||
current_user_role
|
||||
);
|
||||
return null;
|
||||
end;
|
||||
$$;
|
||||
|
||||
create table "audit"."sync_entries" (
|
||||
"id" bigint generated by default as identity not null,
|
||||
"status" text not null,
|
||||
"operation" text not null,
|
||||
"comment" text,
|
||||
"created_at" timestamp with time zone not null default now(),
|
||||
"changed_by_role" text not null
|
||||
);
|
||||
|
||||
create type "audit"."sync_status" as enum ('SUCCESS', 'FAIL');
|
||||
|
||||
alter table "audit"."sync_entries" enable row level security;
|
||||
|
||||
CREATE UNIQUE INDEX sync_entries_pkey ON audit.sync_entries USING btree (id);
|
||||
|
||||
alter table "audit"."sync_entries" add constraint "sync_entries_pkey" PRIMARY KEY using index "sync_entries_pkey";
|
||||
|
||||
create policy "service_role_all"
|
||||
on "audit"."sync_entries"
|
||||
as permissive
|
||||
for all
|
||||
to public
|
||||
using (true);
|
||||
|
||||
GRANT USAGE ON SCHEMA audit TO service_role;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA audit TO service_role;
|
||||
@@ -1,80 +0,0 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
|
||||
const config = {
|
||||
darkMode: ["class"],
|
||||
content: [
|
||||
"./pages/**/*.{ts,tsx}",
|
||||
"./components/**/*.{ts,tsx}",
|
||||
"./app/**/*.{ts,tsx}",
|
||||
"./src/**/*.{ts,tsx}",
|
||||
],
|
||||
prefix: "",
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: "2rem",
|
||||
screens: {
|
||||
"2xl": "1400px",
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive))",
|
||||
foreground: "hsl(var(--destructive-foreground))",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "hsl(var(--popover))",
|
||||
foreground: "hsl(var(--popover-foreground))",
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
},
|
||||
keyframes: {
|
||||
"accordion-down": {
|
||||
from: { height: "0" },
|
||||
to: { height: "var(--radix-accordion-content-height)" },
|
||||
},
|
||||
"accordion-up": {
|
||||
from: { height: "var(--radix-accordion-content-height)" },
|
||||
to: { height: "0" },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
} satisfies Config;
|
||||
|
||||
export default config;
|
||||
Reference in New Issue
Block a user