@mbehenri/openmrs-esm-opentms-meet-app 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +12 -0
- package/.eslintignore +2 -0
- package/.eslintrc +57 -0
- package/.husky/pre-commit +7 -0
- package/.husky/pre-push +6 -0
- package/.prettierignore +14 -0
- package/.turbo.json +18 -0
- package/.yarn/install-state.gz +0 -0
- package/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs +541 -0
- package/.yarn/plugins/@yarnpkg/plugin-outdated.cjs +35 -0
- package/.yarn/releases/yarn-3.6.1.cjs +874 -0
- package/.yarnrc.yml +9 -0
- package/LICENSE +401 -0
- package/README.md +26 -0
- package/__mocks__/react-i18next.js +55 -0
- package/e2e/README.md +115 -0
- package/e2e/core/global-setup.ts +32 -0
- package/e2e/core/index.ts +1 -0
- package/e2e/core/test.ts +20 -0
- package/e2e/fixtures/api.ts +26 -0
- package/e2e/fixtures/index.ts +1 -0
- package/e2e/pages/home-page.ts +9 -0
- package/e2e/pages/index.ts +1 -0
- package/e2e/specs/sample-test.spec.ts +11 -0
- package/e2e/support/github/Dockerfile +34 -0
- package/e2e/support/github/docker-compose.yml +24 -0
- package/e2e/support/github/run-e2e-docker-env.sh +49 -0
- package/example.env +6 -0
- package/i18next-parser.config.js +89 -0
- package/jest.config.js +31 -0
- package/package.json +108 -0
- package/playwright.config.ts +32 -0
- package/src/Extensions/AppointmentTabExt.tsx +23 -0
- package/src/Extensions/DemandTabExt.tsx +14 -0
- package/src/Extensions/MeetIframeExt.tsx +14 -0
- package/src/Extensions/ValidateDemandFormExt.tsx +14 -0
- package/src/assets/img/Logo-texte.png +0 -0
- package/src/assets/img/Logo-texte.sim.white.png +0 -0
- package/src/assets/img/Logo-texte.white.png +0 -0
- package/src/assets/img/Logo.png +0 -0
- package/src/assets/img/favicon.ico +0 -0
- package/src/components/Appointment/index.scss +91 -0
- package/src/components/Appointment/index.tsx +207 -0
- package/src/components/Appointment/menu.scss +7 -0
- package/src/components/Appointment/menu.tsx +48 -0
- package/src/components/Appointment/tab.tsx +162 -0
- package/src/components/Demand/form.scss +19 -0
- package/src/components/Demand/form.tsx +236 -0
- package/src/components/Demand/index.tsx +0 -0
- package/src/components/Demand/tab.scss +145 -0
- package/src/components/Demand/tab.tsx +315 -0
- package/src/components/EmptyLayout/index.scss +69 -0
- package/src/components/EmptyLayout/index.tsx +32 -0
- package/src/components/MeetIframe/index.scss +56 -0
- package/src/components/MeetIframe/index.tsx +117 -0
- package/src/config-schema.ts +45 -0
- package/src/dashboard.meta.ts +12 -0
- package/src/declarations.d.ts +6 -0
- package/src/index.ts +75 -0
- package/src/pages/home/home.component.tsx +8 -0
- package/src/privileges/doctor.ts +213 -0
- package/src/repositories/Opencare/index.ts +12 -0
- package/src/repositories/Opencare/prodRepository.ts +176 -0
- package/src/repositories/Opencare/repository.ts +34 -0
- package/src/repositories/TypeRepository.ts +1 -0
- package/src/repositories/env.ts +7 -0
- package/src/repositories/errors.ts +13 -0
- package/src/root.component.tsx +46 -0
- package/src/root.scss +15 -0
- package/src/root.test.tsx +54 -0
- package/src/routes.json +44 -0
- package/src/services/doctor.ts +165 -0
- package/src/setup-tests.ts +1 -0
- package/src/utils.ts +41 -0
- package/translations/en.json +1 -0
- package/translations/es.json +24 -0
- package/translations/fr.json +24 -0
- package/translations/he.json +24 -0
- package/translations/km.json +24 -0
- package/tsconfig.json +24 -0
- package/webpack.config.js +1 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
2
|
+
|
|
3
|
+
class OpencareRepository {
|
|
4
|
+
async getDemands(): Promise<Array<any>> {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async getAppointments(
|
|
9
|
+
patientUuid: string,
|
|
10
|
+
doctor?: string
|
|
11
|
+
): Promise<Array<any>> {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async rejectDemand(demand_id: string): Promise<void> {}
|
|
16
|
+
|
|
17
|
+
async vaidateDemand(
|
|
18
|
+
demand_id: string,
|
|
19
|
+
doctor_id: string,
|
|
20
|
+
startDate: Date = new Date(),
|
|
21
|
+
duration = 30
|
|
22
|
+
): Promise<void> {}
|
|
23
|
+
|
|
24
|
+
async getProviders(): Promise<Array<any>> {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// must be different for production for the duration of the appointment
|
|
29
|
+
async getTokenNextcloud(username: string): Promise<any> {
|
|
30
|
+
return "TALK_PASSWORD";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default OpencareRepository;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type TypeRepository = "good" | "fake";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class BadResponse extends Error {
|
|
2
|
+
constructor(message = "", name = "") {
|
|
3
|
+
super(message);
|
|
4
|
+
const tabname = ["BAD-RESPONSE"];
|
|
5
|
+
if (name != "") {
|
|
6
|
+
tabname.push(name);
|
|
7
|
+
}
|
|
8
|
+
this.name = tabname.join("-");
|
|
9
|
+
if (Error.captureStackTrace) {
|
|
10
|
+
Error.captureStackTrace(this, this.constructor);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* From here, the application is pretty typical React, but with lots of
|
|
3
|
+
* support from `@openmrs/esm-framework`. Check out `Greeter` to see
|
|
4
|
+
* usage of the configuration system, and check out `PatientGetter` to
|
|
5
|
+
* see data fetching using the OpenMRS FHIR API.
|
|
6
|
+
*
|
|
7
|
+
* Check out the Config docs:
|
|
8
|
+
* https://openmrs.github.io/openmrs-esm-core/#/main/config
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import React, { useEffect } from "react";
|
|
12
|
+
import { BrowserRouter, Route, Routes } from "react-router-dom";
|
|
13
|
+
import { Home } from "./pages/home/home.component";
|
|
14
|
+
import { useConfig } from "@openmrs/esm-framework";
|
|
15
|
+
import env from "./repositories/env";
|
|
16
|
+
// import { useTranslation } from "react-i18next";
|
|
17
|
+
//import styles from "./root.scss";
|
|
18
|
+
|
|
19
|
+
const Root: React.FC = () => {
|
|
20
|
+
// const { t } = useTranslation();
|
|
21
|
+
//const basename = window.getOpenmrsSpaBase() + "home/opencare";
|
|
22
|
+
const basename = window.getOpenmrsSpaBase() + "opencare";
|
|
23
|
+
|
|
24
|
+
//recupération de la configuration
|
|
25
|
+
const conf = useConfig();
|
|
26
|
+
|
|
27
|
+
// update env variable
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
env.API_USER = conf["API_USER"];
|
|
30
|
+
env.API_PASSWORD = conf["API_PASSWORD"];
|
|
31
|
+
env.API_BASE_URL = conf["API_BASE_URL"];
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
33
|
+
return () => {};
|
|
34
|
+
}, [conf]);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<BrowserRouter basename={basename}>
|
|
38
|
+
<Routes>
|
|
39
|
+
{/* Route de la page d'acceuil */}
|
|
40
|
+
<Route path="/home" element={<Home />} />
|
|
41
|
+
</Routes>
|
|
42
|
+
</BrowserRouter>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default Root;
|
package/src/root.scss
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
@use '@carbon/styles/scss/spacing';
|
|
2
|
+
@use '@carbon/styles/scss/type';
|
|
3
|
+
|
|
4
|
+
.container {
|
|
5
|
+
padding: spacing.$spacing-07;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.welcome {
|
|
9
|
+
@include type.type-style('heading-04');
|
|
10
|
+
margin: spacing.$spacing-05 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.explainer {
|
|
14
|
+
margin-bottom: 2rem;
|
|
15
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is the root test for this page. It simply checks that the page
|
|
3
|
+
* renders. If the components of your page are highly interdependent,
|
|
4
|
+
* (e.g., if the `Root` component had state that communicated
|
|
5
|
+
* information between `Greeter` and `PatientGetter`) then you might
|
|
6
|
+
* want to do most of your testing here. If those components are
|
|
7
|
+
* instead quite independent (as is the case in this example), then
|
|
8
|
+
* it would make more sense to test those components independently.
|
|
9
|
+
*
|
|
10
|
+
* The key thing to remember, always, is: write tests that behave like
|
|
11
|
+
* users. They should *look* for elements by their visual
|
|
12
|
+
* characteristics, *interact* with them, and (mostly) *assert* based
|
|
13
|
+
* on things that would be visually apparent to a user.
|
|
14
|
+
*
|
|
15
|
+
* To learn more about how we do testing, see the following resources:
|
|
16
|
+
* https://o3-docs.vercel.app/docs/frontend-modules/testing
|
|
17
|
+
* https://kentcdodds.com/blog/how-to-know-what-to-test
|
|
18
|
+
* https://kentcdodds.com/blog/testing-implementation-details
|
|
19
|
+
* https://kentcdodds.com/blog/common-mistakes-with-react-testing-library
|
|
20
|
+
*
|
|
21
|
+
* Kent C. Dodds is the inventor of `@testing-library`:
|
|
22
|
+
* https://testing-library.com/docs/guiding-principles
|
|
23
|
+
*/
|
|
24
|
+
import React from "react";
|
|
25
|
+
import { render, screen } from "@testing-library/react";
|
|
26
|
+
import { useConfig } from "@openmrs/esm-framework";
|
|
27
|
+
import { type Config } from "./config-schema";
|
|
28
|
+
import Root from "./root.component";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* This is an idiomatic way of dealing with mocked files. Note that
|
|
32
|
+
* `useConfig` is already mocked; the Jest moduleNameMapper (see the
|
|
33
|
+
* Jest config) has mapped the `@openmrs/esm-framework` import to a
|
|
34
|
+
* mock file. This line just tells TypeScript that the object is, in
|
|
35
|
+
* fact, a mock, and so will have methods like `mockReturnValue`.
|
|
36
|
+
*/
|
|
37
|
+
const mockUseConfig = useConfig as jest.Mock;
|
|
38
|
+
|
|
39
|
+
it("renders a landing page for the opencare app", () => {
|
|
40
|
+
const config: Config = {
|
|
41
|
+
API_HOST: "localhost",
|
|
42
|
+
API_PASSWORD: "Admin123",
|
|
43
|
+
API_PORT: "8010",
|
|
44
|
+
API_USER: "admin",
|
|
45
|
+
API_SECURE: false,
|
|
46
|
+
};
|
|
47
|
+
mockUseConfig.mockReturnValue(config);
|
|
48
|
+
|
|
49
|
+
render(<Root />);
|
|
50
|
+
|
|
51
|
+
expect(
|
|
52
|
+
screen.getByRole("heading", { name: /welcome to the o3 opencare app/i })
|
|
53
|
+
).toBeInTheDocument();
|
|
54
|
+
});
|
package/src/routes.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.openmrs.org/routes.schema.json",
|
|
3
|
+
"backendDependencies": {
|
|
4
|
+
"fhir2": ">=1.2",
|
|
5
|
+
"webservices.rest": "^2.24.0"
|
|
6
|
+
},
|
|
7
|
+
"extensions": [
|
|
8
|
+
{
|
|
9
|
+
"component": "demandtab",
|
|
10
|
+
"name": "opencare-demand-tab",
|
|
11
|
+
"slot": "homepage-widgets-slot"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"component": "appointmenttab",
|
|
15
|
+
"name": "opencare-appointment-tab",
|
|
16
|
+
"slot": "patient-chart-appointments-dashboard-slot"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"component": "root",
|
|
20
|
+
"name": "opencare-dashboard",
|
|
21
|
+
"slot": "opencare-dashboard-slot"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"component": "meetiframe",
|
|
25
|
+
"name": "opencare-meet-iframe",
|
|
26
|
+
"meta": {
|
|
27
|
+
"title": {
|
|
28
|
+
"key": "meetWorkspace",
|
|
29
|
+
"default": "Meet Workspace"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"component": "validatedemandform",
|
|
35
|
+
"name": "opencare-validate-demand-form"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"pages": [
|
|
39
|
+
{
|
|
40
|
+
"component": "root",
|
|
41
|
+
"route": "opencare"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { formatDatetime, parseDate } from "@openmrs/esm-framework";
|
|
2
|
+
import { getOpencareRepository } from "../repositories/Opencare";
|
|
3
|
+
import type OpencareRepository from "../repositories/Opencare/repository";
|
|
4
|
+
|
|
5
|
+
export enum AppointmentTypes {
|
|
6
|
+
UPCOMING = 0,
|
|
7
|
+
TODAY = 1,
|
|
8
|
+
PAST = 2,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class DoctorService {
|
|
12
|
+
static instance: DoctorService | null = null;
|
|
13
|
+
|
|
14
|
+
opencare_rep: OpencareRepository;
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
this.opencare_rep = getOpencareRepository("good");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @returns patient service
|
|
23
|
+
*/
|
|
24
|
+
static getInstance(): DoctorService {
|
|
25
|
+
if (DoctorService.instance) {
|
|
26
|
+
return DoctorService.instance;
|
|
27
|
+
} else {
|
|
28
|
+
DoctorService.instance = new DoctorService();
|
|
29
|
+
return DoctorService.instance;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* get the demand in process
|
|
35
|
+
* @param istoday today boolean
|
|
36
|
+
* @returns
|
|
37
|
+
*/
|
|
38
|
+
async getDemands(istoday = false): Promise<Array<any>> {
|
|
39
|
+
try {
|
|
40
|
+
return await this.opencare_rep.getDemands();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
/* console.log(error); */
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* reject the demand in processing
|
|
49
|
+
* @returns
|
|
50
|
+
*/
|
|
51
|
+
async rejectDemand(demand_id: string): Promise<any> {
|
|
52
|
+
try {
|
|
53
|
+
await this.opencare_rep.rejectDemand(demand_id);
|
|
54
|
+
return true;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
/* console.log(error); */
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* validate the demand in processing
|
|
63
|
+
* @returns
|
|
64
|
+
*/
|
|
65
|
+
async validateDemand(
|
|
66
|
+
demand_id: string,
|
|
67
|
+
doctor_id: string,
|
|
68
|
+
startDate: Date = new Date(),
|
|
69
|
+
duration = 30
|
|
70
|
+
): Promise<any> {
|
|
71
|
+
try {
|
|
72
|
+
await this.opencare_rep.vaidateDemand(
|
|
73
|
+
demand_id,
|
|
74
|
+
doctor_id,
|
|
75
|
+
startDate,
|
|
76
|
+
duration
|
|
77
|
+
);
|
|
78
|
+
return true;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
/* console.log(error); */
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* get the appointments
|
|
87
|
+
* @param patientUuid patient uuid
|
|
88
|
+
* @returns
|
|
89
|
+
*/
|
|
90
|
+
async getAppointments(
|
|
91
|
+
patientUuid: string,
|
|
92
|
+
doctor?: string
|
|
93
|
+
): Promise<Map<number, Array<any>>> {
|
|
94
|
+
try {
|
|
95
|
+
const past = [];
|
|
96
|
+
const today = [];
|
|
97
|
+
const upcoming = [];
|
|
98
|
+
|
|
99
|
+
const res = await this.opencare_rep.getAppointments(patientUuid, doctor);
|
|
100
|
+
let datenow = new Date();
|
|
101
|
+
res.forEach((appointment, i) => {
|
|
102
|
+
if (appointment.status != "Cancelled") {
|
|
103
|
+
const dateappt = new Date(appointment.startDateTime);
|
|
104
|
+
|
|
105
|
+
// eslint-disable-next-line no-console
|
|
106
|
+
// console.log(` comp : ${dateappt} - ${datenow}`);
|
|
107
|
+
|
|
108
|
+
if (dateappt > datenow) {
|
|
109
|
+
upcoming.push({
|
|
110
|
+
...appointment,
|
|
111
|
+
appointmentTimeType: AppointmentTypes.UPCOMING,
|
|
112
|
+
});
|
|
113
|
+
} else {
|
|
114
|
+
if (
|
|
115
|
+
dateappt.getDate() === datenow.getDate() &&
|
|
116
|
+
dateappt.getMonth() === datenow.getMonth() &&
|
|
117
|
+
dateappt.getFullYear() === datenow.getFullYear()
|
|
118
|
+
) {
|
|
119
|
+
today.push({
|
|
120
|
+
...appointment,
|
|
121
|
+
appointmentTimeType: AppointmentTypes.TODAY,
|
|
122
|
+
});
|
|
123
|
+
} else {
|
|
124
|
+
past.push({
|
|
125
|
+
...appointment,
|
|
126
|
+
appointmentTimeType: AppointmentTypes.PAST,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
const appointments = new Map<number, Array<any>>();
|
|
133
|
+
appointments.set(AppointmentTypes.PAST, past);
|
|
134
|
+
appointments.set(AppointmentTypes.TODAY, today);
|
|
135
|
+
appointments.set(AppointmentTypes.UPCOMING, upcoming);
|
|
136
|
+
|
|
137
|
+
// eslint-disable-next-line no-console
|
|
138
|
+
// console.log(appointments);
|
|
139
|
+
|
|
140
|
+
return appointments;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async getProviders(): Promise<Array<any>> {
|
|
147
|
+
try {
|
|
148
|
+
return await this.opencare_rep.getProviders();
|
|
149
|
+
} catch (error) {
|
|
150
|
+
/* console.log(error); */
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* get a token for accessing to nextcloud
|
|
157
|
+
* @param istoday today boolean
|
|
158
|
+
* @returns
|
|
159
|
+
*/
|
|
160
|
+
async getTokenNextcloud(username: string): Promise<string> {
|
|
161
|
+
return await this.opencare_rep.getTokenNextcloud(username);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export default DoctorService;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "@testing-library/jest-dom/extend-expect";
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export function base64(str: string): string {
|
|
2
|
+
return btoa(str);
|
|
3
|
+
//return Buffer.from(str).toString('base64')
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function localTimeOffsetUTC() {
|
|
7
|
+
// Obtenir l'offset en minutes
|
|
8
|
+
const now = new Date();
|
|
9
|
+
const timeOffsetMinutes = now.getTimezoneOffset();
|
|
10
|
+
|
|
11
|
+
// Convertir l'offset en heures et minutes
|
|
12
|
+
const hours = Math.floor(Math.abs(timeOffsetMinutes) / 60);
|
|
13
|
+
const minutes = Math.abs(timeOffsetMinutes) % 60;
|
|
14
|
+
const sign = timeOffsetMinutes <= 0 ? "+" : "-";
|
|
15
|
+
|
|
16
|
+
return `${sign}${String(hours).padStart(2, "0")}:${String(minutes).padStart(
|
|
17
|
+
2,
|
|
18
|
+
"0"
|
|
19
|
+
)}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function inLocalTimeOffsetUTC() {
|
|
23
|
+
// Obtenir l'offset en minutes
|
|
24
|
+
const now = new Date();
|
|
25
|
+
const timeOffsetMinutes = now.getTimezoneOffset();
|
|
26
|
+
|
|
27
|
+
// Convertir l'offset en heures et minutes
|
|
28
|
+
const hours = Math.floor(Math.abs(timeOffsetMinutes) / 60);
|
|
29
|
+
const minutes = Math.abs(timeOffsetMinutes) % 60;
|
|
30
|
+
const sign = timeOffsetMinutes >= 0 ? "+" : "-";
|
|
31
|
+
|
|
32
|
+
return `${sign}${String(hours).padStart(2, "0")}:${String(minutes).padStart(
|
|
33
|
+
2,
|
|
34
|
+
"0"
|
|
35
|
+
)}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getPageSizes(data: Array<any>, pageSize = 10): Array<number> {
|
|
39
|
+
const numberOfPages = Math.ceil(data.length / pageSize);
|
|
40
|
+
return Array.from({ length: numberOfPages }, (_, i) => (i + 1) * pageSize);
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"casualGreeting": "hey",
|
|
3
|
+
"configSystem": "Sistema de configuración",
|
|
4
|
+
"configSystemExplainer": "El saludo que se muestra a continuación es impulsado por el sistema de configuración. Para cambiar las propiedades de configuración, haga clic en el icono de llave inglesa en la barra de navegación para abrir el panel Herramientas del implementador. Luego, escriba <2>plantilla</2> en la entrada <4>Configuración de búsqueda</4>. Esto debería filtrar las propiedades de configuración para mostrar solo aquellas que son relevantes para este módulo. Puede cambiar los valores de estas propiedades y hacer clic en <6>Guardar</6> para ver los cambios reflejados en la interfaz de usuario",
|
|
5
|
+
"connect": "Conectar",
|
|
6
|
+
"connectExplainer": "Póngase en contacto con la comunidad",
|
|
7
|
+
"dataFetching": "Obtención de datos",
|
|
8
|
+
"designDocs": "Documentación de diseño",
|
|
9
|
+
"designDocsExplainer": "Lea la documentación de diseño de O3",
|
|
10
|
+
"explainer": "Los siguientes ejemplos demuestran algunas características clave del marco O3",
|
|
11
|
+
"extensionExplainer": "Aquí hay algunos cuadros de colores. Debido a que se adjuntan como extensiones dentro de una ranura, un administrador puede cambiar los cuadros que se muestran mediante la configuración. Estos cuadros están definidos en este módulo, pero podrían adjuntarse a esta ranura incluso si estuvieran en un módulo diferente",
|
|
12
|
+
"extensionSystem": "Sistema de extensión",
|
|
13
|
+
"formalGreeting": "Hola",
|
|
14
|
+
"frontendDocs": "Documentación de interfaz",
|
|
15
|
+
"getPatient": "Consigue una paciente llamada",
|
|
16
|
+
"getStarted": "Comenzar",
|
|
17
|
+
"getStartedExplainer": "Cree un módulo frontend a partir de esta plantilla",
|
|
18
|
+
"learnExplainer": "Aprenda a usar el marco O3.",
|
|
19
|
+
"loading": "Cargando",
|
|
20
|
+
"patientGetterExplainer": "Intente hacer clic en el botón a continuación para buscar un paciente desde el backend",
|
|
21
|
+
"resources": "Recursos",
|
|
22
|
+
"usefulLinks": "A continuación hay algunos enlaces a recursos útiles",
|
|
23
|
+
"welcomeText": "Bienvenido a la aplicación Plantilla O3"
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"casualGreeting": "hey",
|
|
3
|
+
"configSystem": "Système de configuration",
|
|
4
|
+
"configSystemExplainer": "Le message d'accueil affiché ci-dessous est piloté par le système de configuration. Pour modifier les propriétés de configuration, cliquez sur l'icône de clé dans la barre de navigation pour afficher le panneau Outils de mise en œuvre. Saisissez ensuite <2>modèle</2> dans l'entrée <4>Configuration de la recherche</4>. Cela devrait filtrer les propriétés de configuration pour afficher uniquement celles qui sont pertinentes pour ce module. Vous pouvez modifier les valeurs de ces propriétés et cliquer sur <6>Enregistrer</6> pour voir les modifications reflétées dans l'interface utilisateur",
|
|
5
|
+
"connect": "Connecter",
|
|
6
|
+
"connectExplainer": "Entrez en contact avec la communauté",
|
|
7
|
+
"dataFetching": "Récupération de données",
|
|
8
|
+
"designDocs": "Documents de conception",
|
|
9
|
+
"designDocsExplainer": "Lisez la documentation de conception O3",
|
|
10
|
+
"explainer": "Les exemples suivants illustrent certaines fonctionnalités clés du cadre O3",
|
|
11
|
+
"extensionExplainer": "Voici quelques cases colorées. Parce qu'ils sont attachés en tant qu'extensions dans un emplacement, un administrateur peut modifier les cases affichées à l'aide de la configuration. Il se trouve que ces boîtes sont définies dans ce module, mais elles pourraient être attachées à cet emplacement même si elles se trouvaient dans un module différent",
|
|
12
|
+
"extensionSystem": "Système d'extension",
|
|
13
|
+
"formalGreeting": "bonjour",
|
|
14
|
+
"frontendDocs": "Documentation frontale",
|
|
15
|
+
"getPatient": "Obtenez un patient nommé",
|
|
16
|
+
"getStarted": "Commencer",
|
|
17
|
+
"getStartedExplainer": "Créer une interface à partir de ce modèle",
|
|
18
|
+
"learnExplainer": "Apprendre à utiliser le framework O3",
|
|
19
|
+
"loading": "Chargement",
|
|
20
|
+
"patientGetterExplainer": "Essayez de cliquer sur le bouton ci-dessous pour récupérer un patient depuis le backend",
|
|
21
|
+
"resources": "Ressources",
|
|
22
|
+
"usefulLinks": "Ci-dessous quelques liens vers des ressources utiles",
|
|
23
|
+
"welcomeText": "Bienvenue dans l'application O3 Template"
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"casualGreeting": "hey",
|
|
3
|
+
"configSystem": "מערכת התצורה",
|
|
4
|
+
"configSystemExplainer": "הברכה המוצגת להלן מונעת על ידי מערכת התצורה. כדי לשנות את מאפייני התצורה, לחץ על סמל מפתח הברגים בסרגל הניווט כדי למשוך את החלונית Implementer Tools. לאחר מכן, הקלד <2>תבנית</2> בקלט <4>תצורת חיפוש</4>. זה אמור לסנן את מאפייני התצורה כדי להציג רק את אלו הרלוונטיים למודול זה. אתה יכול לשנות את הערכים של מאפיינים אלה וללחוץ על <6>שמור</6> כדי לראות את השינויים המשתקפים בממשק המשתמש",
|
|
5
|
+
"connect": "לְחַבֵּר",
|
|
6
|
+
"connectExplainer": "צור קשר עם הקהילה",
|
|
7
|
+
"dataFetching": "איסוף נתונים",
|
|
8
|
+
"designDocs": "תיעוד עיצוב",
|
|
9
|
+
"designDocsExplainer": "קרא את תיעוד התכנון של O3",
|
|
10
|
+
"explainer": "הדוגמאות הבאות מדגימות כמה תכונות מפתח של מסגרת O3",
|
|
11
|
+
"extensionExplainer": "הנה כמה קופסאות צבעוניות. מכיוון שהם מחוברים כהרחבות בתוך חריץ, מנהל מערכת יכול לשנות אילו תיבות יוצגו באמצעות תצורה. התיבות האלה מוגדרות במקרה במודול הזה, אבל הן יכולות להכנס למשבצת הזו גם אם הן היו במודול אחר",
|
|
12
|
+
"extensionSystem": "מערכת ההרחבה",
|
|
13
|
+
"formalGreeting": "שלום",
|
|
14
|
+
"frontendDocs": "תיעוד חזיתי",
|
|
15
|
+
"getPatient": "קח מטופל בשם",
|
|
16
|
+
"getStarted": "להתחיל",
|
|
17
|
+
"getStartedExplainer": "צור מודול מתבנית זו",
|
|
18
|
+
"learnExplainer": "למד כיצד להשתמש במסגרת O3",
|
|
19
|
+
"loading": "טוען",
|
|
20
|
+
"patientGetterExplainer": "נסה ללחוץ על הכפתור למטה כדי להביא מטופל מאחור",
|
|
21
|
+
"resources": "משאבים נוספים",
|
|
22
|
+
"usefulLinks": "להלן כמה קישורים למשאבים שימושיים",
|
|
23
|
+
"welcomeText": "ברוכים הבאים לאפליקציית O3 Template"
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"casualGreeting": "hey",
|
|
3
|
+
"configSystem": "ប្រព័ន្ធកំណត់រចនាសម្ព័ន្ធ",
|
|
4
|
+
"configSystemExplainer": "ការស្វាគមន៍ដែលបង្ហាញខាងក្រោមត្រូវបានជំរុញដោយប្រព័ន្ធកំណត់រចនាសម្ព័ន្ធ។ ដើម្បីផ្លាស់ប្តូរលក្ខណសម្បត្តិនៃការកំណត់រចនាសម្ព័ន្ធ សូមចុចរូបតំណាង spanner នៅក្នុងរបាររុករក ដើម្បីទាញបន្ទះឧបករណ៍អនុវត្ត។ បន្ទាប់មក វាយ <2>ពុម្ព</2> ទៅក្នុងធាតុបញ្ចូល <4>ការស្វែងរក</4>។ វាគួរត្រងលក្ខណសម្បត្តិនៃការកំណត់រចនាសម្ព័ន្ធ ដើម្បីបង្ហាញតែអ្វីដែលពាក់ព័ន្ធទៅនឹងម៉ូឌុលនេះប៉ុណ្ណោះ។ អ្នកអាចផ្លាស់ប្តូរតម្លៃនៃលក្ខណៈសម្បត្តិទាំងនេះ ហើយចុច <6>រក្សាទុក</6> ដើម្បីមើលការផ្លាស់ប្តូរដែលឆ្លុះបញ្ចាំងនៅក្នុង UI",
|
|
5
|
+
"connect": "ភ្ជាប់",
|
|
6
|
+
"connectExplainer": "ទាក់ទងជាមួយសហគមន៍",
|
|
7
|
+
"dataFetching": "ការទាញយកទិន្នន័យ",
|
|
8
|
+
"designDocs": "ឯកសាររចនា",
|
|
9
|
+
"designDocsExplainer": "អានឯកសាររចនា O3",
|
|
10
|
+
"explainer": "ឧទាហរណ៍ខាងក្រោមបង្ហាញពីលក្ខណៈសំខាន់ៗមួយចំនួននៃក្របខ័ណ្ឌ O3",
|
|
11
|
+
"extensionExplainer": "នេះគឺជាប្រអប់ពណ៌មួយចំនួន។ ដោយសារតែពួកវាត្រូវបានភ្ជាប់ជាផ្នែកបន្ថែមនៅក្នុងរន្ធដោត អ្នកគ្រប់គ្រងអាចផ្លាស់ប្តូរអ្វីដែលប្រអប់ត្រូវបានបង្ហាញដោយប្រើការកំណត់។ ប្រអប់ទាំងនេះត្រូវបានកំណត់នៅក្នុងម៉ូឌុលនេះ ប៉ុន្តែពួកវាអាចភ្ជាប់ជាមួយរន្ធដោតនេះ ទោះបីជាពួកគេស្ថិតនៅក្នុងម៉ូឌុលផ្សេងក៏ដោយ។",
|
|
12
|
+
"extensionSystem": "ប្រព័ន្ធបន្ថែម",
|
|
13
|
+
"formalGreeting": "សួស្តី",
|
|
14
|
+
"frontendDocs": "Frontend docs",
|
|
15
|
+
"getPatient": "យកអ្នកជំងឺឈ្មោះ",
|
|
16
|
+
"getStarted": "ការចាប់ផ្តើម",
|
|
17
|
+
"getStartedExplainer": "បង្កើតម៉ូឌុលផ្នែកខាងមុខពីគំរូនេះ។",
|
|
18
|
+
"learnExplainer": "រៀនពីរបៀបប្រើ O3 framework",
|
|
19
|
+
"loading": "កំពុងផ្ទុក",
|
|
20
|
+
"patientGetterExplainer": "ព្យាយាមចុចប៊ូតុងខាងក្រោមដើម្បីទាញយកអ្នកជំងឺពី API",
|
|
21
|
+
"resources": "ធនធាន",
|
|
22
|
+
"usefulLinks": "ខាងក្រោមនេះគឺជាតំណភ្ជាប់មួយចំនួនទៅកាន់ធនធានដែលមានប្រយោជន៍",
|
|
23
|
+
"welcomeText": "សូមស្វាគមន៍មកកាន់កម្មវិធីគំរូ O3"
|
|
24
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"esModuleInterop": true,
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"allowSyntheticDefaultImports": true,
|
|
6
|
+
"jsx": "react",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"lib": [
|
|
10
|
+
"dom",
|
|
11
|
+
"es5",
|
|
12
|
+
"scripthost",
|
|
13
|
+
"es2015",
|
|
14
|
+
"es2015.promise",
|
|
15
|
+
"es2016.array.include",
|
|
16
|
+
"es2018",
|
|
17
|
+
"es2020",
|
|
18
|
+
"es2022"
|
|
19
|
+
],
|
|
20
|
+
"resolveJsonModule": true,
|
|
21
|
+
"noEmit": true,
|
|
22
|
+
"target": "esnext"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("openmrs/default-webpack-config");
|