MED-105: create analysis results page
This commit is contained in:
@@ -0,0 +1,89 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { ArrowDown } from 'lucide-react';
|
||||||
|
|
||||||
|
import { cn } from '@kit/ui/utils';
|
||||||
|
|
||||||
|
export enum AnalysisResultLevel {
|
||||||
|
VERY_LOW = 0,
|
||||||
|
LOW = 1,
|
||||||
|
NORMAL = 2,
|
||||||
|
HIGH = 3,
|
||||||
|
VERY_HIGH = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Level = ({
|
||||||
|
isActive = false,
|
||||||
|
color,
|
||||||
|
isFirst = false,
|
||||||
|
isLast = false,
|
||||||
|
}: {
|
||||||
|
isActive?: boolean;
|
||||||
|
color: 'destructive' | 'success' | 'warning';
|
||||||
|
isFirst?: boolean;
|
||||||
|
isLast?: boolean;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(`bg-${color} relative h-3 flex-1`, {
|
||||||
|
'opacity-20': !isActive,
|
||||||
|
'rounded-l-lg': isFirst,
|
||||||
|
'rounded-r-lg': isLast,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{isActive && (
|
||||||
|
<div className="absolute top-[-14px] left-1/2 -translate-x-1/2 rounded-[10px] bg-white p-[2px]">
|
||||||
|
<ArrowDown strokeWidth={2} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AnalysisLevelBar = ({
|
||||||
|
normLowerIncluded = true,
|
||||||
|
normUpperIncluded = true,
|
||||||
|
level,
|
||||||
|
}: {
|
||||||
|
normLowerIncluded?: boolean;
|
||||||
|
normUpperIncluded?: boolean;
|
||||||
|
level: AnalysisResultLevel;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="flex h-3 w-full max-w-[360px] gap-1">
|
||||||
|
{normLowerIncluded && (
|
||||||
|
<>
|
||||||
|
<Level
|
||||||
|
isActive={level === AnalysisResultLevel.VERY_LOW}
|
||||||
|
color="destructive"
|
||||||
|
isFirst
|
||||||
|
/>
|
||||||
|
<Level isActive={level === AnalysisResultLevel.LOW} color="warning" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Level
|
||||||
|
isFirst={!normLowerIncluded}
|
||||||
|
isLast={!normUpperIncluded}
|
||||||
|
isActive={level === AnalysisResultLevel.NORMAL}
|
||||||
|
color="success"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{normUpperIncluded && (
|
||||||
|
<>
|
||||||
|
<Level
|
||||||
|
isActive={level === AnalysisResultLevel.HIGH}
|
||||||
|
color="warning"
|
||||||
|
/>
|
||||||
|
<Level
|
||||||
|
isActive={level === AnalysisResultLevel.VERY_HIGH}
|
||||||
|
color="destructive"
|
||||||
|
isLast
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AnalysisLevelBar;
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Info } from 'lucide-react';
|
||||||
|
|
||||||
|
import AnalysisLevelBar, { AnalysisResultLevel } from './analysis-level-bar';
|
||||||
|
|
||||||
|
export enum AnalysisStatus {
|
||||||
|
NORMAL = 0,
|
||||||
|
MEDIUM = 1,
|
||||||
|
HIGH = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Analysis = ({
|
||||||
|
analysis: {
|
||||||
|
name,
|
||||||
|
status,
|
||||||
|
unit,
|
||||||
|
value,
|
||||||
|
normLowerIncluded,
|
||||||
|
normUpperIncluded,
|
||||||
|
normLower,
|
||||||
|
normUpper,
|
||||||
|
},
|
||||||
|
}: {
|
||||||
|
analysis: {
|
||||||
|
name: string;
|
||||||
|
status: AnalysisStatus;
|
||||||
|
unit: string;
|
||||||
|
value: number;
|
||||||
|
normLowerIncluded: boolean;
|
||||||
|
normUpperIncluded: boolean;
|
||||||
|
normLower: number;
|
||||||
|
normUpper: number;
|
||||||
|
};
|
||||||
|
}) => {
|
||||||
|
const isUnderNorm = value < normLower;
|
||||||
|
const getAnalysisResultLevel = () => {
|
||||||
|
if (isUnderNorm) {
|
||||||
|
switch (status) {
|
||||||
|
case AnalysisStatus.MEDIUM:
|
||||||
|
return AnalysisResultLevel.LOW;
|
||||||
|
default:
|
||||||
|
return AnalysisResultLevel.VERY_LOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (status) {
|
||||||
|
case AnalysisStatus.MEDIUM:
|
||||||
|
return AnalysisResultLevel.HIGH;
|
||||||
|
case AnalysisStatus.HIGH:
|
||||||
|
return AnalysisResultLevel.VERY_HIGH;
|
||||||
|
default:
|
||||||
|
return AnalysisResultLevel.NORMAL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="border-border flex items-center justify-between rounded-lg border px-5 py-3">
|
||||||
|
<div className="flex items-center gap-2 font-semibold">
|
||||||
|
{name}
|
||||||
|
<div className="group/tooltip relative">
|
||||||
|
<Info className="hover" />{' '}
|
||||||
|
<div className="absolute bottom-full left-1/2 z-10 mb-2 hidden -translate-x-1/2 rounded bg-gray-800 px-2 py-1 text-sm whitespace-nowrap text-white group-hover/tooltip:block">
|
||||||
|
This text changes when you hover the box above.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="font-semibold">{value}</div>
|
||||||
|
<div className="text-muted-foreground text-sm">{unit}</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-muted-foreground text-center text-sm">
|
||||||
|
{normLower} - {normUpper}
|
||||||
|
<div>Normaalne vahemik</div>
|
||||||
|
</div>
|
||||||
|
<AnalysisLevelBar
|
||||||
|
normLowerIncluded={normLowerIncluded}
|
||||||
|
normUpperIncluded={normUpperIncluded}
|
||||||
|
level={getAnalysisResultLevel()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Analysis;
|
||||||
59
app/home/(user)/(dashboard)/analysis-results/page.tsx
Normal file
59
app/home/(user)/(dashboard)/analysis-results/page.tsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
|
||||||
|
import { withI18n } from '@/lib/i18n/with-i18n';
|
||||||
|
|
||||||
|
import { Trans } from '@kit/ui/makerkit/trans';
|
||||||
|
import { PageBody } from '@kit/ui/page';
|
||||||
|
import { Button } from '@kit/ui/shadcn/button';
|
||||||
|
|
||||||
|
import { loadUserAnalysis } from '../../_lib/server/load-user-analysis';
|
||||||
|
import Analysis, { AnalysisStatus } from './_components/analysis';
|
||||||
|
|
||||||
|
export const generateMetadata = async () => {
|
||||||
|
const i18n = await createI18nServerInstance();
|
||||||
|
const title = i18n.t('account:analysisResults.pageTitle');
|
||||||
|
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
async function AnalysisResultsPage() {
|
||||||
|
const analysisList = await loadUserAnalysis();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageBody>
|
||||||
|
<div className="mt-8 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h4>
|
||||||
|
<Trans i18nKey="account:analysisResults.pageTitle" />
|
||||||
|
</h4>
|
||||||
|
<p className="text-muted-foreground text-sm">
|
||||||
|
<Trans i18nKey="account:analysisResults.description" />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button>
|
||||||
|
<Trans i18nKey="account:analysisResults.orderNewAnalysis" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
{analysisList?.map((analysis, index) => (
|
||||||
|
<Analysis
|
||||||
|
key={index}
|
||||||
|
analysis={{
|
||||||
|
name: analysis.element.analysis_name || '',
|
||||||
|
status: analysis.element.norm_status as AnalysisStatus,
|
||||||
|
unit: analysis.element.unit || '',
|
||||||
|
value: analysis.element.response_value,
|
||||||
|
normLowerIncluded: !!analysis.element.norm_lower_included,
|
||||||
|
normUpperIncluded: !!analysis.element.norm_upper_included,
|
||||||
|
normLower: analysis.element.norm_lower || 0,
|
||||||
|
normUpper: analysis.element.norm_upper || 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</PageBody>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withI18n(AnalysisResultsPage);
|
||||||
22
app/home/(user)/_lib/server/load-user-analysis.ts
Normal file
22
app/home/(user)/_lib/server/load-user-analysis.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { cache } from 'react';
|
||||||
|
|
||||||
|
import { createAccountsApi } from '@kit/accounts/api';
|
||||||
|
import { UserAnalysis } from '@kit/accounts/types/accounts';
|
||||||
|
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||||
|
|
||||||
|
export type UserAccount = Awaited<ReturnType<typeof loadUserAnalysis>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name loadUserAccount
|
||||||
|
* @description
|
||||||
|
* Load the user account. It's a cached per-request function that fetches the user workspace data.
|
||||||
|
* It can be used across the server components to load the user workspace data.
|
||||||
|
*/
|
||||||
|
export const loadUserAnalysis = cache(analysisLoader);
|
||||||
|
|
||||||
|
async function analysisLoader(): Promise<UserAnalysis | null> {
|
||||||
|
const client = getSupabaseServerClient();
|
||||||
|
const api = createAccountsApi(client);
|
||||||
|
|
||||||
|
return api.getUserAnalysis();
|
||||||
|
}
|
||||||
@@ -60,7 +60,7 @@ const pathsConfig = PathsSchema.parse({
|
|||||||
// these routes are added as placeholders and can be changed when the pages are added
|
// these routes are added as placeholders and can be changed when the pages are added
|
||||||
booking: '/booking',
|
booking: '/booking',
|
||||||
myOrders: '/my-orders',
|
myOrders: '/my-orders',
|
||||||
analysisResults: '/analysis-results',
|
analysisResults: '/home/analysis-results',
|
||||||
orderAnalysisPackage: '/order-analysis-package',
|
orderAnalysisPackage: '/order-analysis-package',
|
||||||
orderAnalysis: '/order-analysis',
|
orderAnalysis: '/order-analysis',
|
||||||
orderHealthAnalysis: '/order-health-analysis',
|
orderHealthAnalysis: '/order-health-analysis',
|
||||||
|
|||||||
@@ -617,6 +617,7 @@ export async function syncPrivateMessage(
|
|||||||
response_value: response.VastuseVaartus,
|
response_value: response.VastuseVaartus,
|
||||||
unit: element.Mootyhik ?? null,
|
unit: element.Mootyhik ?? null,
|
||||||
original_response_element: element,
|
original_response_element: element,
|
||||||
|
analysis_name: element.UuringNimi || element.KNimetus,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
"supabase:test": "supabase db test",
|
"supabase:test": "supabase db test",
|
||||||
"supabase:db:reset": "supabase db reset",
|
"supabase:db:reset": "supabase db reset",
|
||||||
"supabase:db:lint": "supabase db lint",
|
"supabase:db:lint": "supabase db lint",
|
||||||
"supabase:db:diff": "supabase db diff",
|
"supabase:db:diff": "supabase db diff --schema auth --schema audit --schema medreport",
|
||||||
"supabase:deploy": "supabase link --project-ref $SUPABASE_PROJECT_REF && supabase db push",
|
"supabase:deploy": "supabase link --project-ref $SUPABASE_PROJECT_REF && supabase db push",
|
||||||
"supabase:typegen": "supabase gen types typescript --local > ./packages/supabase/src/database.types.ts",
|
"supabase:typegen": "supabase gen types typescript --local > ./packages/supabase/src/database.types.ts",
|
||||||
"supabase:db:dump:local": "supabase db dump --local --data-only",
|
"supabase:db:dump:local": "supabase db dump --local --data-only",
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
"./personal-account-settings": "./src/components/personal-account-settings/index.ts",
|
"./personal-account-settings": "./src/components/personal-account-settings/index.ts",
|
||||||
"./components": "./src/components/index.ts",
|
"./components": "./src/components/index.ts",
|
||||||
"./hooks/*": "./src/hooks/*.ts",
|
"./hooks/*": "./src/hooks/*.ts",
|
||||||
"./api": "./src/server/api.ts"
|
"./api": "./src/server/api.ts",
|
||||||
|
"./types/*": "./src/types/*.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^5.1.5"
|
"nanoid": "^5.1.5"
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|||||||
|
|
||||||
import { Database } from '@kit/supabase/database';
|
import { Database } from '@kit/supabase/database';
|
||||||
|
|
||||||
|
import { UserAnalysis } from '../types/accounts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing an API for interacting with user accounts.
|
* Class representing an API for interacting with user accounts.
|
||||||
* @constructor
|
* @constructor
|
||||||
@@ -117,6 +119,7 @@ class AccountsApi {
|
|||||||
*/
|
*/
|
||||||
async getSubscription(accountId: string) {
|
async getSubscription(accountId: string) {
|
||||||
const response = await this.client
|
const response = await this.client
|
||||||
|
.schema('medreport')
|
||||||
.from('subscriptions')
|
.from('subscriptions')
|
||||||
.select('*, items: subscription_items !inner (*)')
|
.select('*, items: subscription_items !inner (*)')
|
||||||
.eq('account_id', accountId)
|
.eq('account_id', accountId)
|
||||||
@@ -168,6 +171,51 @@ class AccountsApi {
|
|||||||
|
|
||||||
return response.data?.customer_id;
|
return response.data?.customer_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getUserAnalysis(): Promise<UserAnalysis | null> {
|
||||||
|
const authUser = await this.client.auth.getUser();
|
||||||
|
const { data, error: userError } = authUser;
|
||||||
|
|
||||||
|
if (userError) {
|
||||||
|
console.error('Failed to get user', userError);
|
||||||
|
throw userError;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { user } = data;
|
||||||
|
|
||||||
|
const { data: analysisResponses } = await this.client
|
||||||
|
.schema('medreport')
|
||||||
|
.from('analysis_responses')
|
||||||
|
.select('*')
|
||||||
|
.eq('user_id', user.id);
|
||||||
|
|
||||||
|
if (!analysisResponses) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const analysisResponseIds = analysisResponses.map((r) => r.id);
|
||||||
|
|
||||||
|
const { data: analysisResponseElements } = await this.client
|
||||||
|
.schema('medreport')
|
||||||
|
.from('analysis_response_elements')
|
||||||
|
.select('*')
|
||||||
|
.in('analysis_response_id', analysisResponseIds);
|
||||||
|
|
||||||
|
if (!analysisResponseElements) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementMap = new Map(
|
||||||
|
analysisResponseElements.map((e) => [e.analysis_response_id, e]),
|
||||||
|
);
|
||||||
|
|
||||||
|
return analysisResponses
|
||||||
|
.filter((r) => elementMap.has(r.id))
|
||||||
|
.map((r) => ({
|
||||||
|
...r,
|
||||||
|
element: elementMap.get(r.id)!,
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createAccountsApi(client: SupabaseClient<Database>) {
|
export function createAccountsApi(client: SupabaseClient<Database>) {
|
||||||
|
|||||||
6
packages/features/accounts/src/types/accounts.ts
Normal file
6
packages/features/accounts/src/types/accounts.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { Database } from '@kit/supabase/database';
|
||||||
|
|
||||||
|
export type UserAnalysis =
|
||||||
|
(Database['medreport']['Tables']['analysis_responses']['Row'] & {
|
||||||
|
element: Database['medreport']['Tables']['analysis_response_elements']['Row'];
|
||||||
|
})[];
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import Medusa from "@medusajs/js-sdk"
|
import Medusa from "@medusajs/js-sdk";
|
||||||
|
|
||||||
// Defaults to standard port for Medusa server
|
// Defaults to standard port for Medusa server
|
||||||
let MEDUSA_BACKEND_URL = "http://localhost:9000"
|
let MEDUSA_BACKEND_URL = "http://localhost:9000";
|
||||||
|
|
||||||
if (process.env.MEDUSA_BACKEND_URL) {
|
if (process.env.MEDUSA_BACKEND_URL) {
|
||||||
MEDUSA_BACKEND_URL = process.env.MEDUSA_BACKEND_URL
|
MEDUSA_BACKEND_URL = process.env.MEDUSA_BACKEND_URL;
|
||||||
}
|
}
|
||||||
|
console.log("MEDUSA_BACKEND_URL", MEDUSA_BACKEND_URL);
|
||||||
export const sdk = new Medusa({
|
export const sdk = new Medusa({
|
||||||
baseUrl: MEDUSA_BACKEND_URL,
|
baseUrl: MEDUSA_BACKEND_URL,
|
||||||
debug: process.env.NODE_ENV === "development",
|
debug: process.env.NODE_ENV === "development",
|
||||||
publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
|
publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
|
||||||
})
|
});
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -37,16 +37,12 @@ function PageWithSidebar(props: PageProps) {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
props.contentContainerClassName ??
|
props.contentContainerClassName ??
|
||||||
'mx-auto flex h-screen w-full flex-col overflow-y-auto bg-inherit'
|
'mx-auto flex h-screen w-full flex-col bg-inherit'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{MobileNavigation}
|
{MobileNavigation}
|
||||||
|
|
||||||
<div
|
<div className={'bg-background flex flex-1 flex-col px-4 lg:px-0'}>
|
||||||
className={
|
|
||||||
'bg-background flex flex-1 flex-col overflow-y-auto px-4 lg:px-0'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{Children}
|
{Children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -75,7 +71,7 @@ function PageWithHeader(props: PageProps) {
|
|||||||
const { Navigation, Children, MobileNavigation } = getSlotsFromPage(props);
|
const { Navigation, Children, MobileNavigation } = getSlotsFromPage(props);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('flex h-screen flex-1 flex-col z-900', props.className)}>
|
<div className={cn('z-900 flex h-screen flex-1 flex-col', props.className)}>
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
props.contentContainerClassName ?? 'flex flex-1 flex-col space-y-4'
|
props.contentContainerClassName ?? 'flex flex-1 flex-col space-y-4'
|
||||||
@@ -83,7 +79,7 @@ function PageWithHeader(props: PageProps) {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-bg-background border-1 light:border-border dark:border-border dark:shadow-primary/10 flex h-15 items-center justify-between px-4 py-1 lg:justify-start lg:shadow-xs border-b',
|
'bg-bg-background light:border-border dark:border-border dark:shadow-primary/10 flex h-15 items-center justify-between border-1 border-b px-4 py-1 lg:justify-start lg:shadow-xs',
|
||||||
{
|
{
|
||||||
'sticky top-0 z-1000 backdrop-blur-md': props.sticky ?? true,
|
'sticky top-0 z-1000 backdrop-blur-md': props.sticky ?? true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -122,5 +122,10 @@
|
|||||||
"consentToAnonymizedCompanyData": {
|
"consentToAnonymizedCompanyData": {
|
||||||
"label": "Consent to be included in employer statistics",
|
"label": "Consent to be included in employer statistics",
|
||||||
"description": "Consent to be included in anonymized company statistics"
|
"description": "Consent to be included in anonymized company statistics"
|
||||||
|
},
|
||||||
|
"analysisResults": {
|
||||||
|
"pageTitle": "My analysis results",
|
||||||
|
"description": "Super, oled käinud tervist kontrollimas. Siin on sinule olulised näitajad:",
|
||||||
|
"orderNewAnalysis": "Telli uued analüüsid"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,5 +145,10 @@
|
|||||||
"successTitle": "Tere, {{firstName}} {{lastName}}",
|
"successTitle": "Tere, {{firstName}} {{lastName}}",
|
||||||
"successDescription": "Teie tervisekonto on aktiveeritud ja kasutamiseks valmis!",
|
"successDescription": "Teie tervisekonto on aktiveeritud ja kasutamiseks valmis!",
|
||||||
"successButton": "Jätka"
|
"successButton": "Jätka"
|
||||||
|
},
|
||||||
|
"analysisResults": {
|
||||||
|
"pageTitle": "Minu analüüside vastused",
|
||||||
|
"description": "Super, oled käinud tervist kontrollimas. Siin on sinule olulised näitajad:",
|
||||||
|
"orderNewAnalysis": "Telli uued analüüsid"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,5 +119,8 @@
|
|||||||
"consentToAnonymizedCompanyData": {
|
"consentToAnonymizedCompanyData": {
|
||||||
"label": "Consent to be included in employer statistics",
|
"label": "Consent to be included in employer statistics",
|
||||||
"description": "Consent to be included in anonymized company statistics"
|
"description": "Consent to be included in anonymized company statistics"
|
||||||
|
},
|
||||||
|
"analysisResults": {
|
||||||
|
"pageTitle": "My analysis results"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
alter table "medreport"."analysis_response_elements" add column "analysis_name" text;
|
||||||
|
|
||||||
|
alter table "medreport"."analysis_response_elements" alter column "response_value" set data type double precision using "response_value"::double precision;
|
||||||
146
supabase/sql/analysis.sql
Normal file
146
supabase/sql/analysis.sql
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
-- Create analysis for /home/analysis-results
|
||||||
|
INSERT INTO medreport.analysis_groups (
|
||||||
|
id,
|
||||||
|
original_id,
|
||||||
|
name,
|
||||||
|
"order",
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
1, -- id
|
||||||
|
'GROUP_ORIG_001', -- original_id
|
||||||
|
'Blood Tests', -- name
|
||||||
|
1, -- order
|
||||||
|
NOW(), -- created_at
|
||||||
|
NOW() -- updated_at
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO medreport.analysis_elements (
|
||||||
|
id,
|
||||||
|
analysis_id_oid,
|
||||||
|
analysis_id_original,
|
||||||
|
tehik_short_loinc,
|
||||||
|
tehik_loinc_name,
|
||||||
|
analysis_name_lab,
|
||||||
|
"order",
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
parent_analysis_group_id,
|
||||||
|
material_groups
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
1, -- id (must match the one used in analyses)
|
||||||
|
'OID12345', -- analysis_id_oid
|
||||||
|
'ORIG123', -- analysis_id_original
|
||||||
|
'LNC123-4', -- tehik_short_loinc
|
||||||
|
'Hemoglobiin', -- tehik_loinc_name
|
||||||
|
'Hemoglobiin (Lab)', -- analysis_name_lab
|
||||||
|
1, -- order
|
||||||
|
NOW(), -- created_at
|
||||||
|
NOW(), -- updated_at
|
||||||
|
1, -- parent_analysis_group_id
|
||||||
|
'{}'::jsonb[] -- material_groups (empty array for now)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO medreport.analyses (
|
||||||
|
id,
|
||||||
|
analysis_id_oid,
|
||||||
|
analysis_id_original,
|
||||||
|
tehik_short_loinc,
|
||||||
|
tehik_loinc_name,
|
||||||
|
analysis_name_lab,
|
||||||
|
"order",
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
parent_analysis_element_id
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
101, -- id
|
||||||
|
'OID12345', -- analysis_id_oid
|
||||||
|
'ORIG123', -- analysis_id_original
|
||||||
|
'LNC123-4', -- tehik_short_loinc
|
||||||
|
'Hemoglobiin', -- tehik_loinc_name
|
||||||
|
'Hemoglobiin (Lab)', -- analysis_name_lab
|
||||||
|
1, -- order
|
||||||
|
NOW(), -- created_at
|
||||||
|
NOW(), -- updated_at
|
||||||
|
1 -- parent_analysis_element_id
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
INSERT INTO medreport.analysis_orders (
|
||||||
|
analysis_element_ids,
|
||||||
|
analysis_ids,
|
||||||
|
user_id,
|
||||||
|
status,
|
||||||
|
id
|
||||||
|
) VALUES (
|
||||||
|
ARRAY[1, 2, 3],
|
||||||
|
ARRAY[101, 102],
|
||||||
|
'8dcb4354-77be-4915-a2cd-8fc573e675d6',
|
||||||
|
'COMPLETED',
|
||||||
|
'10' -- unique id
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO medreport.analysis_responses (
|
||||||
|
id,
|
||||||
|
analysis_order_id,
|
||||||
|
order_number,
|
||||||
|
order_status,
|
||||||
|
user_id
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
'1', -- unique id
|
||||||
|
'10', -- ID of medreport.analysis_orders
|
||||||
|
'123',
|
||||||
|
'COMPLETED',
|
||||||
|
'8dcb4354-77be-4915-a2cd-8fc573e675d6'
|
||||||
|
)
|
||||||
|
ON CONFLICT (order_number)
|
||||||
|
DO UPDATE SET
|
||||||
|
analysis_order_id = EXCLUDED.analysis_order_id,
|
||||||
|
order_status = EXCLUDED.order_status,
|
||||||
|
user_id = EXCLUDED.user_id
|
||||||
|
RETURNING id;
|
||||||
|
|
||||||
|
INSERT INTO medreport.analysis_response_elements (
|
||||||
|
id,
|
||||||
|
analysis_response_id,
|
||||||
|
analysis_element_original_id,
|
||||||
|
unit,
|
||||||
|
response_value,
|
||||||
|
response_time,
|
||||||
|
norm_upper,
|
||||||
|
norm_upper_included,
|
||||||
|
norm_lower,
|
||||||
|
norm_lower_included,
|
||||||
|
norm_status,
|
||||||
|
original_response_element,
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
analysis_name
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
-- Repeat this row for each element
|
||||||
|
(
|
||||||
|
'1000', -- unique id
|
||||||
|
'1', -- ID of medreport.analysis_responses
|
||||||
|
'2',
|
||||||
|
'g/L',
|
||||||
|
146,
|
||||||
|
NOW()::timestamptz,
|
||||||
|
5,
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
3,
|
||||||
|
'{"original_name": "Hgb", "value": 13.5}'::jsonb,
|
||||||
|
NOW(),
|
||||||
|
NOW(),
|
||||||
|
'Hematokrit'
|
||||||
|
);
|
||||||
@@ -3,16 +3,18 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
|
"@kit/ui/*": ["packages/ui/src/*"],
|
||||||
|
"@kit/ui": ["packages/ui/src/index.ts"],
|
||||||
"@lib/*": ["packages/features/medusa-storefront/src/lib/*"],
|
"@lib/*": ["packages/features/medusa-storefront/src/lib/*"],
|
||||||
"@modules/*": ["packages/features/medusa-storefront/src/modules/*"],
|
"@modules/*": ["packages/features/medusa-storefront/src/modules/*"],
|
||||||
"@styles/*": ["packages/features/medusa-storefront/src/styles/*"],
|
"@styles/*": ["packages/features/medusa-storefront/src/styles/*"],
|
||||||
"types/*": ["packages/features/medusa-storefront/src/types/*"],
|
"types/*": ["packages/features/medusa-storefront/src/types/*"],
|
||||||
"@/*": ["./*"],
|
|
||||||
"~/*": ["./app/*"],
|
|
||||||
"~/config/*": ["./config/*"],
|
"~/config/*": ["./config/*"],
|
||||||
"~/components/*": ["./components/*"],
|
"~/components/*": ["./components/*"],
|
||||||
"~/lib/*": ["./lib/*"],
|
"~/lib/*": ["./lib/*"],
|
||||||
"~/medusa/*": ["./packages/features/medusa-storefront/src/*"]
|
"~/medusa/*": ["./packages/features/medusa-storefront/src/*"],
|
||||||
|
"@/*": ["./*"],
|
||||||
|
"~/*": ["./app/*"]
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user