├── ui ├── scripts │ └── package.sh ├── .npmrc ├── react-components │ ├── __mocks__ │ │ ├── styleMock.js │ │ ├── axios.js │ │ └── mockLocalStorage.js │ ├── components │ │ ├── Dropdown │ │ │ ├── IndicatorSeparator.jsx │ │ │ ├── DropdownIndicator.jsx │ │ │ ├── DropdownIndicator.spec.jsx │ │ │ ├── ValueContainer.jsx │ │ │ └── Dropdown.module.scss │ │ ├── DateSelector │ │ │ ├── DateSelector.module.scss │ │ │ ├── DateSelector.spec.jsx │ │ │ └── DateSelector.jsx │ │ ├── AppContext │ │ │ ├── AppContext.js │ │ │ └── AppService.js │ │ ├── AppointmentFilterWrapper │ │ │ ├── FilterWrapper.module.scss │ │ │ └── FilterWrapper.spec.js │ │ ├── Notifications │ │ │ ├── popup.module.scss │ │ │ └── Notifications.jsx │ │ ├── TimeSelector │ │ │ ├── TimeSelector.module.scss │ │ │ ├── TimeSelector.spec.jsx │ │ │ └── TimeSelector.jsx │ │ ├── Title │ │ │ ├── Title.module.scss │ │ │ └── Title.jsx │ │ ├── CustomPopup │ │ │ ├── TestUtil.jsx │ │ │ ├── CustomPopup.module.scss │ │ │ ├── CustomPopup.jsx │ │ │ └── CustomPopup.spec.jsx │ │ ├── Conflicts │ │ │ ├── Footer │ │ │ │ ├── ConflictsFooter.module.scss │ │ │ │ └── ConflictsFooter.jsx │ │ │ ├── Conflicts.module.scss │ │ │ ├── Conflicts.spec.jsx │ │ │ ├── ConflictsUtil.js │ │ │ ├── ServiceUnavailableConflicts.spec.jsx │ │ │ ├── PatientDoubleBookingConflicts.spec.jsx │ │ │ ├── Body │ │ │ │ └── ConflictsBody.module.scss │ │ │ └── Conflicts.jsx │ │ ├── Label │ │ │ ├── Label.module.scss │ │ │ ├── Label.spec.jsx │ │ │ └── Label.jsx │ │ ├── AppointmentNotes │ │ │ ├── AppointmentNotes.module.scss │ │ │ ├── AppointmentNotes.jsx │ │ │ └── AppointmentNotes.spec.jsx │ │ ├── ErrorMessage │ │ │ ├── ErrorMessage.module.scss │ │ │ ├── ErrorMessage.jsx │ │ │ └── ErrorMessage.spec.jsx │ │ ├── ListViewAction │ │ │ ├── usePopupAction.js │ │ │ ├── usePopupAction.spec.js │ │ │ ├── ListViewAction.jsx │ │ │ └── CheckinAction.jsx │ │ ├── AppointmentEditorCommonFieldsWrapper │ │ │ └── AppointmentEditorCommonFieldsWrapper.module.scss │ │ ├── CalendarPicker │ │ │ └── CalendarPicker.module.scss │ │ ├── AppSpecialityFilter │ │ │ └── AppSpecialityFilter.module.scss │ │ ├── TimePicker │ │ │ └── TimePicker.module.scss │ │ ├── AppointmentListSidePanelWrapper │ │ │ └── AppointmentListSidePanelWrapper.module.scss │ │ ├── Print │ │ │ ├── __snapshots__ │ │ │ │ └── Print.spec.jsx.snap │ │ │ ├── Print.spec.jsx │ │ │ └── Print.jsx │ │ ├── EditAppointment │ │ │ ├── UpdateButtons.module.scss │ │ │ ├── EditAppointment.module.scss │ │ │ └── UpdateButtons.spec.jsx │ │ ├── ButtonGroup │ │ │ ├── ButtonGroup.module.scss │ │ │ └── ButtonGroup.jsx │ │ ├── TabView │ │ │ ├── TabView.spec.jsx │ │ │ ├── TabView.module.scss │ │ │ └── TabView.jsx │ │ ├── DatePicker │ │ │ └── DateInput.module.scss │ │ ├── RadioGroup │ │ │ ├── RecurrenceTypeRadioGroup.module.scss │ │ │ ├── RadioButton.module.scss │ │ │ └── RadioGroup.module.scss │ │ ├── AppointmentListSidePanelSearch │ │ │ ├── AppointmentListSidePanelSearch.module.scss │ │ │ └── AppointmentListSidePanelSearch.spec.jsx │ │ ├── NumberInput │ │ │ └── NumberInputCarbon.jsx │ │ ├── AppointmentType │ │ │ ├── AppointmentType.spec.jsx │ │ │ └── AppointmentType.jsx │ │ ├── ToggleButton │ │ │ ├── ToggleButton.module.scss │ │ │ ├── ToggleButton.jsx │ │ │ └── ToggleButton.test.jsx │ │ ├── AppointmentEditorFooter │ │ │ └── AppointmentEditorFooter.module.scss │ │ ├── InputNumber │ │ │ ├── InputNumber.module.scss │ │ │ └── InputNumber.jsx │ │ ├── DateOrWeekNavigator │ │ │ └── DateOrWeekNavigator.module.scss │ │ ├── ColorPicker │ │ │ └── ColorPicker.module.scss │ │ ├── CancelConfirmation │ │ │ ├── CancelConfirmation.module.scss │ │ │ ├── CancelConfirmation.jsx │ │ │ └── CancelConfirmation.spec.jsx │ │ ├── UpdateConfirmationModal │ │ │ ├── UpdateConfirmationModal.spec.jsx │ │ │ └── UpdateConfirmationModal.module.scss │ │ ├── Tags │ │ │ └── Tags.jsx │ │ ├── DropdownCarbon │ │ │ └── Dropdown.jsx │ │ ├── SuccessModal │ │ │ └── SuccessModal.module.scss │ │ ├── DatePickerCarbon │ │ │ └── DatePickerCarbon.jsx │ │ ├── AddAppointment │ │ │ └── AddAppointmentService.js │ │ └── AppointmentCategory │ │ │ └── AppointmentCategory.jsx │ ├── utils │ │ ├── __mocks__ │ │ │ └── CookieUtil.js │ │ ├── CookieUtil.js │ │ ├── LocalStorageUtil.js │ │ ├── hooks │ │ │ ├── useFocusLock.jsx │ │ │ └── useOutsideClick.js │ │ ├── AppointmentUtil.js │ │ ├── TestUtil.js │ │ ├── MergeObjectUtil.js │ │ ├── DateOrWeekNavigator │ │ │ └── weekDatesHelper.js │ │ ├── AppointmentListSidePanelWrapper │ │ │ ├── getFilteredNodesOnToggle.js │ │ │ ├── transformTreeData.js │ │ │ └── getFilteredNodesOnSearch.js │ │ └── DateUtil.js │ ├── carbon-conflict-fixes.scss │ ├── containers │ │ └── AddAppointmentContainer.jsx │ ├── mapper │ │ ├── providerMapper.js │ │ ├── patientMapper.js │ │ └── patientMapper.spec.js │ ├── stories │ │ ├── util.js │ │ ├── DateOrWeekNavigator.stories.js │ │ ├── Print.stories.js │ │ ├── AppointmentListSidePanelSearch.stories.js │ │ ├── DateInput.stories.js │ │ ├── ProviderSearch.stories.js │ │ ├── AppointmentStatus.stories.js │ │ ├── LocationSearch.stories.js │ │ ├── GridSummary.stories.js │ │ ├── FilterWrapper.stories.js │ │ ├── Tags.stories.js │ │ ├── TabView.stories.js │ │ ├── AppSpecialityFilter.stories.js │ │ ├── ToggleButton.stories.js │ │ ├── ListViewAction.stories.js │ │ └── Dropdown.stories.js │ ├── api │ │ ├── specialityApi.js │ │ ├── locationApi.js │ │ ├── __mocks__ │ │ │ └── specialityApi.js │ │ ├── serviceApi.js │ │ ├── providerApi.js │ │ ├── specialityApi.spec.js │ │ ├── recurringAppointmentsApi.js │ │ ├── configApi.js │ │ ├── translationsApi.js │ │ ├── patientApi.js │ │ └── appointmentsApi.js │ ├── bahmni-theme.scss │ ├── variables.scss │ └── config.js ├── notes ├── .babelrc ├── i18n │ └── appointments │ │ └── index.js ├── config │ └── jest │ │ ├── cssTransform.js │ │ └── fileTransform.js ├── .storybook │ └── config.js └── local-react-config.js ├── .npmrc ├── package ├── .appversion ├── docker │ └── Dockerfile ├── resources │ └── appointments_ssl.conf ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── helm │ ├── Chart.yaml │ ├── values.yaml │ ├── .helmignore │ └── templates │ │ ├── service.yaml │ │ └── hpa.yaml ├── scripts │ ├── preuninstall.sh │ ├── preinstall.sh │ └── postinstall.sh └── build.gradle ├── src ├── views │ ├── manage │ │ ├── editAppointment.html │ │ ├── calendar │ │ │ ├── dayCalendar.html │ │ │ ├── weekCalendar.html │ │ │ └── calendarView.html │ │ ├── patientSearch.html │ │ ├── datePicker.html │ │ ├── appointmentsManage.html │ │ ├── weekPicker.html │ │ ├── appointmentConflictConfirmation.html │ │ ├── allAppointments.html │ │ └── multiSelectAutocomplete.html │ ├── admin │ │ ├── appointmentsAdmin.html │ │ ├── colorPicker.html │ │ ├── deleteAppointmentService.html │ │ ├── appointmentServiceNavigationConfirmation.html │ │ ├── serviceAttributes.html │ │ ├── serviceTypeDeleteConfirmation.html │ │ └── serviceTypes.html │ ├── appointmentsHeader.html │ └── checkInPopUp.html ├── favicon.ico ├── images │ ├── next.png │ ├── prev.png │ ├── loader.gif │ ├── spinner.gif │ ├── copy_24px.png │ └── spinner-small.gif ├── styles │ ├── fonts │ │ ├── icomoon.eot │ │ ├── icomoon.ttf │ │ ├── icomoon.woff │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── fontawesome-webfont.woff2 │ │ ├── opensans-bold-webfont.eot │ │ ├── opensans-bold-webfont.ttf │ │ ├── opensans-italic-webfont.eot │ │ ├── opensans-italic-webfont.ttf │ │ ├── opensans-light-webfont.eot │ │ ├── opensans-light-webfont.ttf │ │ ├── opensans-italic-webfont.woff │ │ ├── opensans-regular-webfont.eot │ │ ├── opensans-regular-webfont.ttf │ │ ├── opensans-semibold-webfont.eot │ │ ├── opensans-semibold-webfont.ttf │ │ └── bahmni-custom-fonts │ │ │ ├── bahmni-custom-fonts.eot │ │ │ ├── bahmni-custom-fonts.ttf │ │ │ └── bahmni-custom-fonts.woff │ ├── common │ │ ├── _angularFix.scss │ │ ├── _confirmBox.scss │ │ └── _directives.scss │ ├── clinical │ │ └── _clinicalIndex.scss │ ├── bahmni-components │ │ ├── _loader.scss │ │ ├── _tooltip.scss │ │ ├── _header.scss │ │ └── _autoComplete.scss │ ├── appointments │ │ ├── components.scss │ │ ├── _calenderStyles.scss │ │ └── _appSummary.scss │ └── appointmentScheduling.scss ├── route-errorhandler.js ├── directives │ ├── dayCalendar.js │ ├── weekCalendar.js │ ├── colorPicker.js │ └── timeValidator.js ├── index.html ├── services │ ├── specialityService.js │ └── checkinPopUp.js ├── appointmentInitialization.js ├── appointmentServiceInitialization.js ├── loadConstants.js ├── controllers │ ├── admin │ │ └── deleteAppointmentServiceController.js │ ├── appointmentsHeaderController.js │ └── manage │ │ └── allAppointmentsController.js ├── initialization.js └── debugUiRouter.js ├── .eslintignore ├── .csslintrc ├── lib └── jquery │ └── images │ ├── animated-overlay.gif │ ├── ui-icons_222222_256x240.png │ ├── ui-icons_228ef1_256x240.png │ ├── ui-icons_ef8c08_256x240.png │ ├── ui-icons_ffd27a_256x240.png │ ├── ui-icons_ffffff_256x240.png │ ├── ui-bg_flat_10_000000_40x100.png │ ├── ui-bg_glass_65_ffffff_1x400.png │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ └── ui-bg_highlight-soft_75_ffe45c_1x100.png ├── NOTICE ├── .tx └── config ├── .gitignore ├── .codeclimate.yml ├── .github └── workflows │ ├── validate_pull_request.yml │ └── pull_translations.yml ├── test ├── support │ └── helpers.js ├── data │ └── addressHierarchyEntry.json ├── services │ ├── specialityService.spec.js │ └── providerService.spec.js └── appointmentServiceInitialization.spec.js ├── .travis.yml ├── config └── react-config.json ├── karma.conf.js └── .eslintrc /ui/scripts/package.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true -------------------------------------------------------------------------------- /package/.appversion: -------------------------------------------------------------------------------- 1 | 1.2.0 -------------------------------------------------------------------------------- /ui/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true -------------------------------------------------------------------------------- /ui/react-components/__mocks__/styleMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; -------------------------------------------------------------------------------- /src/views/manage/editAppointment.html: -------------------------------------------------------------------------------- 1 |
edit appointment
-------------------------------------------------------------------------------- /src/views/admin/appointmentsAdmin.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | dist/ 3 | node_modules/ 4 | coverage/ 5 | output/ 6 | test/ 7 | **/*{.,-}min.js 8 | -------------------------------------------------------------------------------- /ui/react-components/__mocks__/axios.js: -------------------------------------------------------------------------------- 1 | import mockAxios from 'jest-mock-axios'; 2 | export default mockAxios; -------------------------------------------------------------------------------- /package/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM httpd:2.4.62-alpine3.20 2 | COPY dist/. /usr/local/apache2/htdocs/appointments/ -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /ui/react-components/components/Dropdown/IndicatorSeparator.jsx: -------------------------------------------------------------------------------- 1 | export const IndicatorSeparator = () => null; 2 | -------------------------------------------------------------------------------- /package/resources/appointments_ssl.conf: -------------------------------------------------------------------------------- 1 | #For Appointments Frontend 2 | Alias /appointments /var/www/appointments 3 | -------------------------------------------------------------------------------- /src/images/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/images/next.png -------------------------------------------------------------------------------- /src/images/prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/images/prev.png -------------------------------------------------------------------------------- /src/images/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/images/loader.gif -------------------------------------------------------------------------------- /src/images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/images/spinner.gif -------------------------------------------------------------------------------- /.csslintrc: -------------------------------------------------------------------------------- 1 | --exclude-exts=.min.css 2 | --ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes 3 | -------------------------------------------------------------------------------- /src/images/copy_24px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/images/copy_24px.png -------------------------------------------------------------------------------- /ui/react-components/components/DateSelector/DateSelector.module.scss: -------------------------------------------------------------------------------- 1 | .appointmentDatePicker { 2 | margin-top: 20px; 3 | } 4 | -------------------------------------------------------------------------------- /src/images/spinner-small.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/images/spinner-small.gif -------------------------------------------------------------------------------- /src/styles/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/icomoon.eot -------------------------------------------------------------------------------- /src/styles/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/icomoon.ttf -------------------------------------------------------------------------------- /src/styles/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/icomoon.woff -------------------------------------------------------------------------------- /ui/react-components/utils/__mocks__/CookieUtil.js: -------------------------------------------------------------------------------- 1 | 2 | export const currentLocation = () => { 3 | return {uuid: 'uuid'}; 4 | }; 5 | -------------------------------------------------------------------------------- /src/styles/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /ui/react-components/components/AppContext/AppContext.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const AppContext = React.createContext({}); 4 | -------------------------------------------------------------------------------- /lib/jquery/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/animated-overlay.gif -------------------------------------------------------------------------------- /ui/notes: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | uid: 12222224, 4 | provider: null, 5 | srtTime: 12333, 6 | endTime: 2235, 7 | 8 | } 9 | ] -------------------------------------------------------------------------------- /package/gradle.properties: -------------------------------------------------------------------------------- 1 | #these properties will be set in go task. During testing, the following values are considered. 2 | version=0.93 3 | buildNumber=1 4 | -------------------------------------------------------------------------------- /package/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/package/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /package/helm/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: appointments 3 | description: Helm chart for bahmni appointments module 4 | type: application 5 | version: 1.0.0 -------------------------------------------------------------------------------- /src/styles/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/styles/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/styles/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/styles/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/styles/fonts/opensans-bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-bold-webfont.eot -------------------------------------------------------------------------------- /src/styles/fonts/opensans-bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-bold-webfont.ttf -------------------------------------------------------------------------------- /src/styles/fonts/opensans-italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-italic-webfont.eot -------------------------------------------------------------------------------- /src/styles/fonts/opensans-italic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-italic-webfont.ttf -------------------------------------------------------------------------------- /src/styles/fonts/opensans-light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-light-webfont.eot -------------------------------------------------------------------------------- /src/styles/fonts/opensans-light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-light-webfont.ttf -------------------------------------------------------------------------------- /lib/jquery/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /package/scripts/preuninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $1 -eq 0 ]; then 3 | rm -rf /var/www/appointments 4 | rm -rf /etc/httpd/conf.d/appointments_ssl.conf 5 | fi 6 | -------------------------------------------------------------------------------- /src/styles/common/_angularFix.scss: -------------------------------------------------------------------------------- 1 | [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], 2 | .ng-cloak, .x-ng-cloak, 3 | .ng-hide { 4 | display: none !important; 5 | } -------------------------------------------------------------------------------- /src/styles/fonts/opensans-italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-italic-webfont.woff -------------------------------------------------------------------------------- /src/styles/fonts/opensans-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-regular-webfont.eot -------------------------------------------------------------------------------- /src/styles/fonts/opensans-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-regular-webfont.ttf -------------------------------------------------------------------------------- /src/styles/fonts/opensans-semibold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-semibold-webfont.eot -------------------------------------------------------------------------------- /src/styles/fonts/opensans-semibold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/opensans-semibold-webfont.ttf -------------------------------------------------------------------------------- /ui/react-components/components/AppointmentFilterWrapper/FilterWrapper.module.scss: -------------------------------------------------------------------------------- 1 | .appointmentFilterItems { 2 | margin-bottom: 5px; 3 | padding: 0 20px 10px; 4 | } -------------------------------------------------------------------------------- /lib/jquery/images/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /package/scripts/preinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf /opt/bahmni-appointments-frontend/ 4 | rm -rf /var/www/appointments 5 | rm -f /etc/httpd/conf.d/appointments_ssl.conf 6 | -------------------------------------------------------------------------------- /ui/react-components/carbon-conflict-fixes.scss: -------------------------------------------------------------------------------- 1 | button[class*="bx--"]{ 2 | &:hover{ 3 | background-image: none; 4 | } 5 | margin: 0; 6 | background-image: none; 7 | } 8 | -------------------------------------------------------------------------------- /lib/jquery/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /lib/jquery/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/lib/jquery/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /ui/react-components/components/Notifications/popup.module.scss: -------------------------------------------------------------------------------- 1 | .alertContainer { 2 | position: fixed; 3 | top: 80px; 4 | right: 0; 5 | z-index: 999; 6 | width: 500px; 7 | left: 35%; 8 | } -------------------------------------------------------------------------------- /ui/react-components/components/TimeSelector/TimeSelector.module.scss: -------------------------------------------------------------------------------- 1 | .timeSelector { 2 | margin-top: 20px; 3 | 4 | > div { 5 | display: inline-block; 6 | width: 42%; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /ui/react-components/utils/CookieUtil.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie'; 2 | 3 | export const currentLocation = () => { 4 | return JSON.parse(Cookies.get('bahmni.user.location')); 5 | }; 6 | -------------------------------------------------------------------------------- /src/styles/fonts/bahmni-custom-fonts/bahmni-custom-fonts.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/bahmni-custom-fonts/bahmni-custom-fonts.eot -------------------------------------------------------------------------------- /src/styles/fonts/bahmni-custom-fonts/bahmni-custom-fonts.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/bahmni-custom-fonts/bahmni-custom-fonts.ttf -------------------------------------------------------------------------------- /src/styles/fonts/bahmni-custom-fonts/bahmni-custom-fonts.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bahmni/openmrs-module-appointments-frontend/HEAD/src/styles/fonts/bahmni-custom-fonts/bahmni-custom-fonts.woff -------------------------------------------------------------------------------- /ui/react-components/components/Title/Title.module.scss: -------------------------------------------------------------------------------- 1 | .title{ 2 | font-family: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif; 3 | font-size: 12px; 4 | } 5 | .required{ 6 | color: #da1e28; 7 | } 8 | -------------------------------------------------------------------------------- /ui/react-components/components/CustomPopup/TestUtil.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const TestUtil = () => { 4 | return( 5 |
6 | Text 7 |
8 | ) 9 | }; 10 | -------------------------------------------------------------------------------- /src/views/appointmentsHeader.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 |
-------------------------------------------------------------------------------- /ui/react-components/components/Conflicts/Footer/ConflictsFooter.module.scss: -------------------------------------------------------------------------------- 1 | .conflictsFooter { 2 | background: #f2f2f2; 3 | position: fixed; 4 | width: calc(100% - 64px); 5 | z-index: 600; 6 | bottom: 0; 7 | } 8 | -------------------------------------------------------------------------------- /src/styles/clinical/_clinicalIndex.scss: -------------------------------------------------------------------------------- 1 | 2 | body{ 3 | font-size: 14px; 4 | //@media (max-width : 768px){ 5 | // font-size: 15px; 6 | //} 7 | } 8 | .consultation-content{ 9 | margin-top: 45px; 10 | } 11 | -------------------------------------------------------------------------------- /ui/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "plugins": [ 4 | ["@babel/plugin-transform-runtime", 5 | { 6 | "regenerator": true 7 | } 8 | ] 9 | ] 10 | } -------------------------------------------------------------------------------- /ui/i18n/appointments/index.js: -------------------------------------------------------------------------------- 1 | import en from './locale_en.json'; 2 | import es from './locale_es.json'; 3 | import fr from './locale_fr.json'; 4 | import ptBr from './locale_pt_BR.json'; 5 | 6 | export default{en, es, fr, ptBr}; 7 | -------------------------------------------------------------------------------- /ui/react-components/__mocks__/mockLocalStorage.js: -------------------------------------------------------------------------------- 1 | import 'jest-localstorage-mock'; 2 | import {localReactConfig} from '../../local-react-config'; 3 | 4 | localStorage.setItem("reactConfig", JSON.stringify(localReactConfig)); 5 | -------------------------------------------------------------------------------- /ui/react-components/components/Label/Label.module.scss: -------------------------------------------------------------------------------- 1 | .disabledLabelContainer { 2 | cursor: not-allowed; 3 | opacity: 0.5; 4 | } 5 | .carbonFont{ 6 | font-family: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif; 7 | } 8 | -------------------------------------------------------------------------------- /src/views/manage/calendar/dayCalendar.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | -------------------------------------------------------------------------------- /src/views/manage/calendar/weekCalendar.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | -------------------------------------------------------------------------------- /ui/react-components/components/AppointmentNotes/AppointmentNotes.module.scss: -------------------------------------------------------------------------------- 1 | .notes { 2 | height: calc(100% - 104px); 3 | width: calc(100% - 20px); 4 | padding: 10px; 5 | border-radius: 4px; 6 | border: solid 1px #7e7e7e; 7 | resize: none; 8 | } 9 | -------------------------------------------------------------------------------- /package/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jul 22 11:49:28 IST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip 7 | -------------------------------------------------------------------------------- /ui/react-components/components/ErrorMessage/ErrorMessage.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .messageHolder { 4 | margin: 5px; 5 | height: 15px; 6 | font-size: 12px; 7 | color: #da1e28; 8 | font-family: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif; 9 | } 10 | -------------------------------------------------------------------------------- /src/route-errorhandler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('bahmni.common.routeErrorHandler', ['ui.router']) 4 | .run(['$rootScope', function ($rootScope) { 5 | $rootScope.$on('$stateChangeError', function (event) { 6 | event.preventDefault(); 7 | }); 8 | }]); 9 | -------------------------------------------------------------------------------- /ui/react-components/components/ListViewAction/usePopupAction.js: -------------------------------------------------------------------------------- 1 | import {useState} from "react"; 2 | 3 | export default function usePopupAction() { 4 | const [show, setShow] = useState(true); 5 | 6 | const handleClose = () => setShow(false); 7 | 8 | return {show, handleClose}; 9 | }; 10 | -------------------------------------------------------------------------------- /ui/react-components/components/AppointmentEditorCommonFieldsWrapper/AppointmentEditorCommonFieldsWrapper.module.scss: -------------------------------------------------------------------------------- 1 | .tableWrapper{ 2 | tr{ 3 | border-bottom: none; 4 | } 5 | tr > td{ 6 | border: none; 7 | padding: 2px; 8 | vertical-align: baseline; 9 | width: 50%; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ui/react-components/components/CalendarPicker/CalendarPicker.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .calendarPickerContainer { 4 | button { 5 | background: none; 6 | border: none; 7 | padding: 0; 8 | } 9 | position: absolute; 10 | width: 20%; 11 | margin-left: 0.4em; 12 | } 13 | -------------------------------------------------------------------------------- /ui/react-components/utils/LocalStorageUtil.js: -------------------------------------------------------------------------------- 1 | import {helpDeskNumber} from "../constants"; 2 | 3 | export const getLocale = () => { 4 | return localStorage.getItem('NG_TRANSLATE_LANG_KEY'); 5 | }; 6 | 7 | export const getHelpDeskNumber = () => { 8 | return localStorage.getItem(helpDeskNumber); 9 | }; 10 | -------------------------------------------------------------------------------- /ui/react-components/utils/hooks/useFocusLock.jsx: -------------------------------------------------------------------------------- 1 | import FocusLock from "react-focus-lock"; 2 | import React from "react"; 3 | 4 | const useFocusLock = WrappedComponent => props => 5 | ( 6 | 7 | ); 8 | 9 | export default useFocusLock; 10 | -------------------------------------------------------------------------------- /ui/react-components/components/AppSpecialityFilter/AppSpecialityFilter.module.scss: -------------------------------------------------------------------------------- 1 | 2 | .faCheck { 3 | color: #218fef; 4 | } 5 | 6 | .faUncheck { 7 | color: #979797; 8 | } 9 | 10 | 11 | .faExpand,.faClose{ 12 | font-size: 20px; 13 | line-height: 12px; 14 | position: relative; 15 | bottom: 0px; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /ui/react-components/components/Dropdown/DropdownIndicator.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import {dropdownIndicator} from "./Dropdown.module.scss"; 3 | import React from "react"; 4 | 5 | export const DropdownIndicator = () => { 6 | return ; 7 | }; 8 | -------------------------------------------------------------------------------- /ui/react-components/components/TimePicker/TimePicker.module.scss: -------------------------------------------------------------------------------- 1 | .appointmentTimePicker { 2 | width: 58%; 3 | 4 | input[class^='rc-time-picker-input'] { 5 | border-radius: 4px; 6 | padding: 5px 3px; 7 | } 8 | } 9 | 10 | .appointmentTimePickerPopup { 11 | div[class^='rc-time-picker-panel-inner']{ 12 | width: 20em; 13 | } 14 | } -------------------------------------------------------------------------------- /ui/react-components/containers/AddAppointmentContainer.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { AppointmentEditor } from "../AppointmentEditor/AppointmentEditor.jsx"; 3 | 4 | // TODO : need to add connection to redux 5 | const AddAppointmentContainer = () => { 6 | return (); 7 | } 8 | 9 | export default AddAppointmentContainer; 10 | -------------------------------------------------------------------------------- /ui/react-components/mapper/providerMapper.js: -------------------------------------------------------------------------------- 1 | export const getProviderDropDownOptions = (providers) => { 2 | return providers.map(provider => { 3 | return { 4 | label: provider.name, 5 | value: provider.uuid, 6 | comments: provider.comments, 7 | response: provider.response 8 | } 9 | }); 10 | }; 11 | -------------------------------------------------------------------------------- /ui/react-components/stories/util.js: -------------------------------------------------------------------------------- 1 | import { IntlProvider } from "react-intl"; 2 | import React from "react"; 3 | 4 | export const withReactIntl = (Component, messages = {}) => { 5 | return (props) => { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /ui/react-components/components/CustomPopup/CustomPopup.module.scss: -------------------------------------------------------------------------------- 1 | .customPopup { 2 | 3 | div[class^='popup-content'] { 4 | margin-top: 7% !important; 5 | width: 470px !important; 6 | } 7 | } 8 | 9 | .conflictsPopup{ 10 | div[class^='popup-content'] { 11 | margin: 3% 0 0 35% !important; 12 | width: 65% !important; 13 | height: auto; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ui/react-components/utils/AppointmentUtil.js: -------------------------------------------------------------------------------- 1 | import {APPOINTMENT_STATUSES} from "../constants"; 2 | 3 | export const isAppointmentScheduledOrCheckedIn = (appointment) => { 4 | return appointment.status === APPOINTMENT_STATUSES.Scheduled 5 | || appointment.status === APPOINTMENT_STATUSES.CheckedIn 6 | || appointment.status === APPOINTMENT_STATUSES.Requested; 7 | }; 8 | -------------------------------------------------------------------------------- /ui/react-components/api/specialityApi.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import {specialityUrl} from "../config"; 3 | 4 | export const getAllSpecialities = async () => { 5 | try { 6 | const response = await axios.get(specialityUrl); 7 | return response.data; 8 | } catch (error) { 9 | console.error(error); 10 | return error.response; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /ui/react-components/components/AppointmentListSidePanelWrapper/AppointmentListSidePanelWrapper.module.scss: -------------------------------------------------------------------------------- 1 | .showSelectedContainer { 2 | display: flex; 3 | justify-content: space-between; 4 | align-items: center; 5 | font-family: OpenSans, Arial, sans-serif, Arial, sans-serif; 6 | font-size: 14px; 7 | margin: 20px 0; 8 | 9 | b { 10 | font-weight: lighter; 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /ui/config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/en/webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /ui/react-components/stories/DateOrWeekNavigator.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import DateOrWeekNavigator from "../components/DateOrWeekNavigator/DateOrWeekNavigator"; 3 | 4 | export default { title: 'DateOrWeekNavigator' }; 5 | 6 | export const dayView = () => ( ); 7 | 8 | export const weekView = () => ( ); -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 OpenMRS, Inc 2 | 3 | This product includes software developed under the stewardship of the Bahmni Coalition, under fiscal sponsorship of OpenMRS, Inc. (http://www.openmrs.org/) 4 | 5 | This product includes software developed at ThoughtWorks, Inc. (http://www.thoughtworks.com/) 6 | 7 | This software contains code derived from the RAXA-JSS Registration. (https://github.com/Raxa/Raxa-JSS). 8 | -------------------------------------------------------------------------------- /ui/react-components/stories/Print.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Print from '../components/Print/Print'; 3 | 4 | export default { title: 'Print' }; 5 | 6 | export const basic = () => ( 7 | 8 | <> 9 |
Appointments
10 |

This print icon prints all the elements provided as children to it

11 | 12 |
13 | ); 14 | -------------------------------------------------------------------------------- /ui/react-components/components/Print/__snapshots__/Print.spec.jsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Print render print icon 1`] = ` 4 | 5 | 23 | handlePrint()} data-testid="printIcon"> 24 | 25 | ) 26 | } -------------------------------------------------------------------------------- /ui/react-components/components/EditAppointment/EditAppointment.module.scss: -------------------------------------------------------------------------------- 1 | .editAppointment { 2 | .currentTimeSlot { 3 | margin-top: 15px; 4 | font-size: 16px; 5 | margin-bottom: 50px; 6 | } 7 | .recurringDetailsEdit { 8 | > div { 9 | margin-bottom: 35px; 10 | .recurringTerminationDetails { 11 | > div { 12 | margin-bottom: 15px; 13 | } 14 | } 15 | .weekDaySelector { 16 | margin: 10px 0; 17 | } 18 | } 19 | .recurringEndDateContainer { 20 | > div { 21 | display: flex; 22 | } 23 | .recurringEndDateLabel { 24 | font-size: 16px; 25 | } 26 | .dateText { 27 | &:before { 28 | content: "|"; 29 | padding: 3px; 30 | } 31 | } 32 | } 33 | 34 | } 35 | 36 | .appointmentPlanContainer { 37 | width: 70%; 38 | margin-bottom: 25px; 39 | } 40 | } 41 | .recurring{ 42 | min-height: 140%; 43 | } 44 | -------------------------------------------------------------------------------- /ui/react-components/components/AppointmentType/AppointmentType.spec.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {renderWithReactIntl} from '../../utils/TestUtil'; 3 | import AppointmentType from "./AppointmentType.jsx"; 4 | 5 | 6 | describe('Appointment type', () => { 7 | it('should render the Appointment Type component', () => { 8 | const {container, getByText, getByTestId} = renderWithReactIntl(); 9 | expect(getByText('Teleconsultation')).not.toBeNull(); 10 | expect(container.querySelector('.bx--checkbox-label')).not.toBeNull(); 11 | expect(getByTestId('add-tele-consultation')).not.toBeNull(); 12 | }); 13 | 14 | it('should disable the teleconsulting when isTeleconsultationDisabled is true', () => { 15 | const {container} = renderWithReactIntl(); 16 | expect(container.querySelectorAll('.bx--checkbox-label')[0]).not.toBeUndefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /ui/react-components/components/ToggleButton/ToggleButton.module.scss: -------------------------------------------------------------------------------- 1 | @import "../../variables.scss"; 2 | 3 | .toggleBtnCheckbox { 4 | height: 0; 5 | width: 0; 6 | visibility: hidden; 7 | } 8 | 9 | .toggleBtnLabel { 10 | display: flex; 11 | align-items: center; 12 | justify-content: space-between; 13 | cursor: pointer; 14 | width: 40px; 15 | height: 15px; 16 | background: grey; 17 | border-radius: 100px; 18 | position: relative; 19 | //transition: background-color 0.2s; 20 | } 21 | 22 | .toggleBtnLabel .toggleBtnSlider { 23 | content: ""; 24 | position: absolute; 25 | width: 20px; 26 | height: 20px; 27 | border-radius: 45px; 28 | //transition: 1s; 29 | background: #fff; 30 | box-shadow: 0 0 2px 0 rgba(10, 10, 10, 0.29); 31 | } 32 | 33 | .toggleBtnCheckbox:checked + .toggleBtnLabel .toggleBtnSlider { 34 | left: 100%; 35 | transform: translateX(-100%); 36 | } 37 | 38 | .toggleBtnLabel:active .toggleBtnSlider { 39 | width: 20px; 40 | } 41 | -------------------------------------------------------------------------------- /ui/react-components/mapper/patientMapper.js: -------------------------------------------------------------------------------- 1 | export const getPatientName = (patient) => { 2 | const givenName = patient.givenName ? patient.givenName : ''; 3 | const familyName = patient.familyName ? patient.familyName : ''; 4 | return givenName && familyName ? `${givenName} ${familyName}` : `${givenName}` || `${familyName}`; 5 | }; 6 | 7 | export const getPatientForDropdown = patient => { 8 | const {identifier, uuid} = patient; 9 | const name = patient.name || getPatientName(patient); 10 | return { 11 | value: {name, identifier, uuid}, 12 | label: `${name} (${patient.identifier})` 13 | }; 14 | }; 15 | 16 | export const mapOpenMRSPatient = patient => { 17 | const displays = patient.display.split(" - "); 18 | const name = displays[1]; 19 | const identifier = displays[0]; 20 | const uuid = patient.uuid; 21 | return { 22 | value: {name, identifier, uuid}, 23 | label: `${name} (${identifier})` 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /src/loadConstants.js: -------------------------------------------------------------------------------- 1 | export async function loadAngularConstants() { 2 | return fetch("./config/ng-config.json") 3 | .then((res) => { 4 | return res.json().then((data) => { 5 | window.Bahmni = window.Bahmni || {}; 6 | 7 | window.Bahmni.Common = window.Bahmni.Common || {}; 8 | window.Bahmni.Common.Constants = data.Common.Constants; 9 | 10 | window.Bahmni.Appointments = window.Bahmni.Appointments || {}; 11 | window.Bahmni.Appointments.Constants = data.Appointments.Constants; 12 | }) 13 | }) 14 | } 15 | 16 | export async function loadReactConstants() { 17 | //todo: cache the JSON constants files 18 | // https://bahmni.atlassian.net/browse/AP-21 19 | return fetch("./config/react-config.json") 20 | .then((res) => 21 | res.json().then((data) => { 22 | localStorage.setItem("reactConfig", JSON.stringify(data)); 23 | }) 24 | ); 25 | } -------------------------------------------------------------------------------- /src/views/admin/appointmentServiceNavigationConfirmation.html: -------------------------------------------------------------------------------- 1 |
2 | 4 | 9 |
10 |

{{'NAVIGATION_CONFIRMATION_DIALOG_MESSAGE_KEY' | translate}}

11 |
12 | 13 |
14 | 15 | 16 |
17 | 18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /src/views/manage/appointmentConflictConfirmation.html: -------------------------------------------------------------------------------- 1 |
2 | 4 | 9 |
10 |

{{'SAVE_CONFIRMATION_DIALOG_CONFLICT_KEY' | translate}}

11 |
12 |
13 | 15 | 17 |
18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /package/scripts/postinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -f /etc/bahmni-installer/bahmni.conf ]; then 4 | . /etc/bahmni-installer/bahmni.conf 5 | fi 6 | 7 | #create bahmni user and group if doesn't exist 8 | USERID=bahmni 9 | GROUPID=bahmni 10 | /bin/id -g $GROUPID 2>/dev/null 11 | [ $? -eq 1 ] 12 | groupadd bahmni 13 | 14 | /bin/id $USERID 2>/dev/null 15 | [ $? -eq 1 ] 16 | useradd -g bahmni bahmni 17 | 18 | 19 | setupApps(){ 20 | ln -s /opt/bahmni-appointments-frontend/etc/appointments/ /var/www/appointments 21 | } 22 | 23 | setupConfFiles() { 24 | cp -f /opt/bahmni-appointments-frontend/etc/appointments_ssl.conf /etc/httpd/conf.d/appointments_ssl.conf 25 | } 26 | 27 | manage_permissions(){ 28 | # permissions 29 | chown -R bahmni:bahmni /opt/bahmni-appointments-frontend 30 | chown -R bahmni:bahmni /var/www/appointments 31 | chown -R bahmni:bahmni /etc/httpd/conf.d/appointments_ssl.conf 32 | } 33 | 34 | setupApps 35 | setupConfFiles 36 | manage_permissions 37 | 38 | service httpd reload || true 39 | -------------------------------------------------------------------------------- /ui/react-components/stories/ListViewAction.stories.js: -------------------------------------------------------------------------------- 1 | import CheckinAction from "../components/ListViewAction/CheckinAction"; 2 | import ListViewAction from "../components/ListViewAction/ListViewAction"; 3 | import {IntlProvider} from "react-intl"; 4 | import React from "react"; 5 | 6 | 7 | const messages = { 8 | "YES_KEY": "Yes", 9 | "NO_KEY": "No", 10 | "APPOINTMENT_STATUS_CHANGE_CONFIRM_MESSAGE": "Are you sure, you want to mark appointment as {toStatus}?" 11 | }; 12 | 13 | export default {title: 'List View Actions'}; 14 | export const missed = () => ; 15 | export const checkin = () => ; 16 | export const complete = () => ; 17 | export const cancel = () => ; 18 | -------------------------------------------------------------------------------- /src/services/checkinPopUp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('bahmni.common.uiHelper') 4 | .service('checkinPopUp', ['$rootScope', 'ngDialog', function ($rootScope, ngDialog) { 5 | var confirmBox = function (config) { 6 | var dialog; 7 | var scope = config.scope; 8 | scope.checkedInAppointment = {time: moment().seconds(0).milliseconds(0).toDate()}; 9 | scope.close = function () { 10 | ngDialog.close(dialog.id); 11 | scope.$destroy(); 12 | }; 13 | dialog = ngDialog.open({ 14 | plain: true, 15 | template: require('../views/checkInPopUp.html'), 16 | scope: scope, 17 | className: config.className || 'ngdialog-theme-default' 18 | }); 19 | 20 | scope.performAction = function () { 21 | scope.action(scope.checkedInAppointment.time, scope.close); 22 | }; 23 | }; 24 | return confirmBox; 25 | }]); 26 | -------------------------------------------------------------------------------- /ui/react-components/api/specialityApi.spec.js: -------------------------------------------------------------------------------- 1 | import mockAxios from "jest-mock-axios"; 2 | import {specialityUrl} from "../config"; 3 | import {getAllSpecialities} from "./specialityApi"; 4 | 5 | afterEach(() => { 6 | mockAxios.reset(); 7 | }); 8 | 9 | describe('Speciality service', () => { 10 | it('should return specialities', async () => { 11 | let mockResponse = [ 12 | { 13 | "name": "SpecialityOne", 14 | "uuid": "SpecialityOneUuid" 15 | }, 16 | { 17 | "name": "SpecialityTwo", 18 | "uuid": "SpecialityTwoUuid" 19 | } 20 | ]; 21 | mockAxios.get.mockImplementationOnce(() => 22 | Promise.resolve({ 23 | data: mockResponse 24 | }) 25 | ); 26 | 27 | let specialities = await getAllSpecialities(); 28 | 29 | expect(mockAxios.get).toHaveBeenCalledWith(specialityUrl); 30 | expect(specialities).toEqual(mockResponse); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /ui/react-components/components/ListViewAction/ListViewAction.jsx: -------------------------------------------------------------------------------- 1 | import CustomPopup from "../CustomPopup/CustomPopup"; 2 | import {popup} from "./ListViewAction.module.scss"; 3 | import {useIntl} from "react-intl"; 4 | import React from "react"; 5 | import usePopupAction from "./usePopupAction"; 6 | 7 | export default function ListViewAction({status = "Completed"}) { 8 | const {show, handleClose} = usePopupAction(); 9 | const intl = useIntl(); 10 | 11 | function content() { 12 | return ( 13 | <> 14 |

{intl.formatMessage({id: "APPOINTMENT_STATUS_CHANGE_CONFIRM_MESSAGE"}, {toStatus: status})}

15 | 16 | 17 | 18 | ) 19 | } 20 | 21 | { 22 | return show && 23 | 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /test/data/addressHierarchyEntry.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent" : { 3 | "addressHierarchyEntryId": 1, 4 | "name": "Barisal", 5 | "levelId": 1, 6 | "addressHierarchyLevel": { 7 | "levelId": 1, 8 | "name": "Division", 9 | "parentLevelId": null, 10 | "addressField": "STATE_PROVINCE", 11 | "required": true, 12 | "uuid": "c25a0952-7d55-11e5-acdf-90fba67c4298", 13 | "id": 1 14 | }, 15 | "parentId": null, 16 | "userGeneratedId": "10", 17 | "uuid": "b3f2af24-ae8f-4699-83d9-78e0d97ba976" 18 | }, 19 | 20 | "child" : { 21 | "addressHierarchyEntryId": 2, 22 | "name": "Barguna", 23 | "levelId": 2, 24 | "addressHierarchyLevel": { 25 | "levelId": 2, 26 | "name": "Zilla", 27 | "parentLevelId": 1, 28 | "addressField": "COUNTY_DISTRICT", 29 | "required": true, 30 | "uuid": "c25a3285-7d55-11e5-acdf-90fba67c4298", 31 | "id": 2 32 | }, 33 | "parentId": 1, 34 | "userGeneratedId": "1004", 35 | "uuid": "559ba00d-d2d6-443e-be7b-f4e9fb7265fb" 36 | } 37 | } -------------------------------------------------------------------------------- /ui/react-components/components/AppointmentEditorFooter/AppointmentEditorFooter.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | .errorMessageContainer { 3 | margin-left: 25px; 4 | } 5 | 6 | .footer { 7 | background: #f2f2f2; 8 | position: fixed; 9 | width: calc(100% - 64px); 10 | z-index: 55; 11 | bottom: 0; 12 | 13 | .footerElements { 14 | float: right; 15 | position: fixed; 16 | right: 32px; 17 | 18 | .button { 19 | background: #f2f2f2; 20 | height: 50px; 21 | border: 0; 22 | border-radius: 0; 23 | padding: 0 21px; 24 | position: relative; 25 | top: -50px; 26 | span { 27 | margin: auto 5px; 28 | } 29 | 30 | &:hover:not(.save) { 31 | background: darkgrey; 32 | } 33 | 34 | } 35 | .save { 36 | color: $secondary-color-1; 37 | background: $primary-color-2; 38 | &:not([disabled]) { 39 | &:hover { 40 | background: $primary-color-2; 41 | opacity: 1; 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /package/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "nebula.ospackage" version "3.4.0" 3 | } 4 | 5 | group 'org.bahmni.appointments' 6 | version project.version 7 | 8 | task extractAppointments(type: Copy){ 9 | from zipTree(file("${projectDir}/resources/appointments.zip")) 10 | into file("${projectDir}/resources/appointments") 11 | } 12 | 13 | ospackage { 14 | packageName = 'bahmni-appointments-frontend' 15 | release = System.getenv('GO_PIPELINE_COUNTER') ?: project.buildNumber 16 | arch = NOARCH 17 | os = LINUX 18 | user = 'root' 19 | 20 | into '/opt/bahmni-appointments-frontend' 21 | 22 | from("${projectDir}/resources/") { 23 | fileMode = 0755 24 | createDirectoryEntry = true 25 | into 'etc' 26 | exclude('appointments.zip') 27 | } 28 | } 29 | 30 | buildRpm { 31 | dependsOn "extractAppointments" 32 | 33 | preInstall file("${projectDir}/scripts/preinstall.sh") 34 | postInstall file("${projectDir}/scripts/postinstall.sh") 35 | preUninstall file("${projectDir}/scripts/preuninstall.sh") 36 | } 37 | -------------------------------------------------------------------------------- /src/controllers/admin/deleteAppointmentServiceController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('bahmni.appointments') 4 | .controller('deleteAppointmentServiceController', ['$scope', 'appointmentsServiceService', 'messagingService', 'ngDialog', '$state', 5 | function ($scope, appointmentsServiceService, messagingService, ngDialog, $state) { 6 | $scope.service = $scope.ngDialogData.service; 7 | 8 | $scope.deleteServiceConfirmation = function () { 9 | return appointmentsServiceService.deleteAppointmentService($scope.service.uuid).then(function () { 10 | messagingService.showMessage('info', "{{'APPOINTMENT_SERVICE_DELETE_SUCCESS_MESSAGE_KEY' | translate}}"); 11 | ngDialog.close(); 12 | $state.reload(); 13 | }, function () { 14 | ngDialog.close(); 15 | }); 16 | }; 17 | 18 | $scope.cancelDeleteService = function () { 19 | ngDialog.close(); 20 | }; 21 | }]); 22 | -------------------------------------------------------------------------------- /ui/react-components/stories/Dropdown.stories.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Dropdown from "../components/Dropdown/Dropdown"; 3 | import { withReactIntl } from "./util"; 4 | 5 | export default { title: "Dropdown" }; 6 | 7 | const colourOptions = [ 8 | { value: "ocean", label: "Ocean" }, 9 | { value: "blue", label: "Blue" }, 10 | { value: "orange", label: "Orange" }, 11 | { value: "yellow", label: "Yellow" }, 12 | { value: "green", label: "Green" }, 13 | { value: "forest", label: "Forest" }, 14 | { value: "slate", label: "Slate" }, 15 | { value: "silver", label: "Silver" }, 16 | ]; 17 | 18 | const InternationalizedDropDown = withReactIntl(Dropdown, { 19 | DROPDOWN_NO_OPTIONS_MESSAGE: "no option", 20 | }); 21 | 22 | export const withPlaceholder = () => ( 23 | 24 | ); 25 | 26 | export const withOptions = () => ( 27 | 31 | ); 32 | -------------------------------------------------------------------------------- /src/views/admin/serviceAttributes.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 8 | 17 |

18 |
19 |
20 | -------------------------------------------------------------------------------- /src/views/admin/serviceTypeDeleteConfirmation.html: -------------------------------------------------------------------------------- 1 |
2 | 4 | 9 |
10 |

{{'APPOINTMENT_SERVICE_TYPE_CONFORMATION_POPUP_MESSAGE_FOR_DELETE' | translate}}: {{ ngDialogData.serviceType.name }}?

11 |
12 | 13 |
14 | 15 | 16 |
17 | 18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /ui/react-components/components/InputNumber/InputNumber.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .inputNumberContainer { 4 | display: inline-flex; 5 | border-bottom: 1px solid $border-color; 6 | padding-bottom: 1px; 7 | margin: 0 5% 0 5%; 8 | .inputButton { 9 | color: $secondary-color-1; 10 | cursor: pointer; 11 | background-color: $primary-color-1; 12 | height: 16px; 13 | width: 25px; 14 | font-size: 10px; 15 | border: none; 16 | } 17 | .inputButton:hover { 18 | background-color: $border-color; 19 | } 20 | 21 | input::-webkit-outer-spin-button, 22 | input::-webkit-inner-spin-button { 23 | -webkit-appearance: none; 24 | margin: 0; 25 | } 26 | input[type=number] { 27 | -moz-appearance: textfield; 28 | border: none; 29 | width: 39px; 30 | text-align: center; 31 | height: 12px; 32 | &:focus { 33 | outline: none; 34 | } 35 | } 36 | } 37 | 38 | .disable { 39 | cursor: not-allowed; 40 | div:first-child { 41 | pointer-events: none; 42 | opacity: 0.5; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/services/specialityService.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('SpecialityService', function () { 4 | var specialityService, mockHttp; 5 | mockHttp = jasmine.createSpyObj('$http', ['get', 'post']); 6 | mockHttp.get.and.callFake(function (params) { 7 | return specUtil.respondWith({data: {}}); 8 | }); 9 | mockHttp.post.and.callFake(function (params) { 10 | return specUtil.respondWith({data: {}}); 11 | }); 12 | 13 | beforeEach(function () { 14 | module('bahmni.appointments'); 15 | module(function ($provide) { 16 | $provide.value('$http', mockHttp); 17 | }); 18 | inject(['specialityService', function (_specialityService_) { 19 | specialityService = _specialityService_; 20 | }]); 21 | }); 22 | 23 | it('should get all specialities', function () { 24 | specialityService.getAllSpecialities(); 25 | expect(mockHttp.get).toHaveBeenCalledWith(Bahmni.Appointments.Constants.getAllSpecialitiesUrl, 26 | jasmine.any(Object)); 27 | }); 28 | }); 29 | 30 | -------------------------------------------------------------------------------- /ui/react-components/components/RadioGroup/RadioGroup.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | input[type="radio"] { 4 | appearance: none; 5 | margin: 0 10px 0 0; 6 | width: 12px; 7 | height: 12px; 8 | box-shadow: inset 0 0 0 .2em white, 9 | 0 0 0 .1em; 10 | border-radius: 50%; 11 | transition: .2s; 12 | cursor: pointer; 13 | color: $border-color; 14 | 15 | &:checked { 16 | background: $primary-color-1; 17 | box-shadow: inset 0 0 0 .2em white, 18 | 0 0 0 .1em $primary-color-1; 19 | } 20 | } 21 | 22 | .radioButton { 23 | display: flex; 24 | margin: 5% 4% 4% 0; 25 | align-items: center; 26 | height: 20px; 27 | 28 | div { 29 | display: flex; 30 | } 31 | input { 32 | min-width: 12px; 33 | } 34 | 35 | } 36 | 37 | .grayOut { 38 | opacity: 0.6; 39 | display: flex; 40 | margin: 5% 4% 4% 0; 41 | align-items: center; 42 | height: 20px; 43 | } 44 | 45 | div[disabled] { 46 | pointer-events: none; 47 | opacity: 0.7; 48 | } 49 | 50 | 51 | .dateText { 52 | &:before { 53 | content: "|"; 54 | padding: 3px; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ui/react-components/components/Conflicts/ServiceUnavailableConflicts.spec.jsx: -------------------------------------------------------------------------------- 1 | import {renderWithReactIntl} from "../../utils/TestUtil"; 2 | import React from "react"; 3 | import ServiceUnavailableConflicts from "./ServiceUnavailableConflicts"; 4 | 5 | describe('ServiceUnavailableConflicts', () => { 6 | it('should render service conflicts content', () => { 7 | const service = {label: 'Orthopedic'}; 8 | const conflicts = { 9 | SERVICE_UNAVAILABLE: [{service: {name: "Orthopedic"}, startDateTime: 1575561600000}, 10 | {service: {name: "Orthopedic"}, startDateTime: 1576861600000}] 11 | }; 12 | 13 | const {getByText} = renderWithReactIntl(); 15 | 16 | getByText('The Orthopedic service you had selected for the appointment(s) is not available during below ' + 17 | 'listed dates'); 18 | getByText('5th December ‘19 | Thursday | 4:00 PM'); 19 | getByText('20th December ‘19 | Friday | 5:06 PM'); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /ui/react-components/components/DateOrWeekNavigator/DateOrWeekNavigator.module.scss: -------------------------------------------------------------------------------- 1 | .weekNavigator { 2 | text-align: center; 3 | box-sizing: border-box; 4 | top: 126px; 5 | right: 179px; 6 | 7 | 8 | button, input { 9 | background: #F8F8F8; 10 | border: none; 11 | outline: none; 12 | font-size: 14px; 13 | padding: 8px 10px; 14 | border-radius: 3px; 15 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); 16 | transition: all 0.3s cubic-bezier(.25, .8, .25, 1); 17 | display: inline-block; 18 | color: #000; 19 | margin-left: 10px; 20 | &:hover { 21 | box-shadow: 0 4px 9px rgba(0, 0, 0, 0.25), 0 5px 5px rgba(0, 0, 0, 0.22); 22 | opacity: 1; 23 | } 24 | } 25 | 26 | .labelForDate{ 27 | width: 115px; 28 | position: absolute; 29 | cursor: pointer; 30 | background: #F8F8F8; 31 | padding: 9px; 32 | margin-left: 10px; 33 | margin-top: 5px; 34 | } 35 | 36 | input { 37 | width: 155px; 38 | position: initial; 39 | font-family: OpenSans, Arial, sans-serif, Arial, sans-serif;; 40 | } 41 | } -------------------------------------------------------------------------------- /ui/react-components/components/Conflicts/PatientDoubleBookingConflicts.spec.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PatientDoubleBookingConflicts from "./PatientDoubleBookingConflicts"; 3 | import {renderWithReactIntl} from "../../utils/TestUtil"; 4 | 5 | describe('PatientDoubleBookingConflicts', () => { 6 | 7 | it('should render patient double booking conflicts content', () => { 8 | const service = {label: 'Orthopedic'}; 9 | const conflicts = {PATIENT_DOUBLE_BOOKING: [{service: {name: "Dressing"}, startDateTime: 1575561600000}]}; 10 | const {container, getByText} = renderWithReactIntl(); 12 | 13 | getByText('The appointment you are trying to book overlaps with the following dates'); 14 | getByText('5th December ‘19 | Thursday | 4:00 PM'); 15 | expect(container.querySelector('.conflictMessage').innerHTML).toContain('Current Orthopedic request'); 16 | expect(container.querySelector('strong').innerHTML).toContain('Dressing'); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /ui/react-components/components/DateSelector/DateSelector.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Label from "../Label/Label.jsx"; 4 | import AppointmentDatePicker from "../DatePicker/DatePicker.jsx"; 5 | import {injectIntl} from "react-intl"; 6 | import classNames from 'classnames'; 7 | import {appointmentDatePicker} from './DateSelector.module.scss' 8 | 9 | const DateSelector = props => { 10 | const {translationKey, defaultValue, onChange, onClear} = props; 11 | 12 | return ( 13 |
14 |
19 | ) 20 | }; 21 | 22 | 23 | DateSelector.propTypes = { 24 | intl: PropTypes.object.isRequired, 25 | onChange: PropTypes.func.isRequired, 26 | defaultValue: PropTypes.string.isRequired, 27 | translationKey: PropTypes.string 28 | }; 29 | 30 | export default injectIntl(DateSelector); 31 | -------------------------------------------------------------------------------- /src/directives/colorPicker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('bahmni.appointments') 4 | .directive('colorPicker', ['$document', function ($document) { 5 | return { 6 | restrict: "E", 7 | scope: { 8 | colors: "=", 9 | selectedColor: '=' 10 | }, 11 | template: require("../views/admin/colorPicker.html"), 12 | link: function (scope) { 13 | scope.showTheColorPicker = function (event) { 14 | scope.showColorPicker = !scope.showColorPicker; 15 | event.stopPropagation(); 16 | }; 17 | 18 | scope.setColor = function (color, event) { 19 | scope.selectedColor = color; 20 | scope.showColorPicker = false; 21 | event.stopPropagation(); 22 | }; 23 | 24 | $document.bind("click", function (ev) { 25 | scope.showColorPicker = false; 26 | scope.$digest(); 27 | }); 28 | } 29 | }; 30 | }]); 31 | -------------------------------------------------------------------------------- /package/helm/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ .Chart.Name }} 6 | labels: 7 | app: {{ .Chart.Name }} 8 | environment: {{ .Values.metadata.labels.environment }} 9 | spec: 10 | scaleTargetRef: 11 | apiVersion: apps/v1 12 | kind: Deployment 13 | name: {{ .Chart.Name }} 14 | minReplicas: {{ .Values.autoscaling.minReplicas }} 15 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 16 | metrics: 17 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 18 | - type: Resource 19 | resource: 20 | name: cpu 21 | target: 22 | type: Utilization 23 | averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 24 | {{- end }} 25 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 26 | - type: Resource 27 | resource: 28 | name: memory 29 | target: 30 | type: Utilization 31 | averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 32 | {{- end }} 33 | {{- end }} 34 | -------------------------------------------------------------------------------- /ui/react-components/components/Notifications/Notifications.jsx: -------------------------------------------------------------------------------- 1 | import React, {useEffect, useRef} from "react"; 2 | import classNames from 'classnames'; 3 | import {alertContainer} from "./popup.module.scss" 4 | import { InlineNotification } from "carbon-components-react"; 5 | 6 | const Notifications = props => { 7 | const {showMessage = false, title, onClose, messageDuration=5000} = props 8 | const ref = useRef(null) 9 | useEffect(()=>{ 10 | if(showMessage){ 11 | if(ref.current){ 12 | clearTimeout(ref.current) 13 | } 14 | ref.current = setTimeout(() => { 15 | onClose(); 16 | }, messageDuration); 17 | } 18 | },[showMessage]) 19 | 20 | return ( 21 |
22 | {showMessage &&
23 | 28 |
29 | } 30 |
31 | ); 32 | }; 33 | 34 | export default Notifications; 35 | -------------------------------------------------------------------------------- /src/views/manage/calendar/calendarView.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 5 | 7 | 8 |

{{::'NO_APPOINTMENT_CALENDAR_VIEW' | translate}}

9 | 11 | 13 |
14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /ui/react-components/components/Conflicts/Body/ConflictsBody.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../variables.scss'; 2 | 3 | .conflictsCount { 4 | &:before { 5 | content: "-"; 6 | padding: 3px; 7 | } 8 | } 9 | 10 | .conflictsHeading { 11 | position: relative; 12 | font-weight: 400; 13 | font-size: 14px; 14 | line-height: 18px; 15 | color: #393939; 16 | } 17 | 18 | .conflictsList { 19 | height: 600px; 20 | overflow: auto 21 | } 22 | 23 | .appointmentConflict { 24 | margin-top: 2.5%; 25 | font-size: 14px; 26 | .conflictMessage { 27 | color: #393939; 28 | padding-bottom: 10px; 29 | } 30 | .conflictDetails { 31 | position: relative; 32 | font-weight: 400; 33 | font-size: 14px; 34 | color: #393939; 35 | } 36 | } 37 | 38 | .conflictsWarningMessage { 39 | display: inline-block; 40 | position: relative; 41 | font-size: 20px; 42 | color: #393939; 43 | margin-left: 30px; 44 | } 45 | 46 | .tabPanelContent { 47 | overflow: auto; 48 | } 49 | 50 | .conflictsBody { 51 | max-width: 540px; 52 | padding: 0 16px; 53 | -webkit-box-sizing: border-box; 54 | } 55 | 56 | .conflictsTabs { 57 | padding-top: 15px 58 | } -------------------------------------------------------------------------------- /src/styles/bahmni-components/_header.scss: -------------------------------------------------------------------------------- 1 | .header-wrapper{ 2 | background: $bahmniSecondaryColor; 3 | header{ 4 | height:52px; 5 | max-width:$max-page-width; 6 | margin: 0 auto; 7 | position: relative; 8 | @media screen and (max-width: $max-page-width) { 9 | padding: 0 10px; 10 | } 11 | } 12 | } 13 | 14 | .patient-details { 15 | display: inline-block; 16 | position: fixed; 17 | top: 53px; 18 | right: 5px; 19 | z-index: 1; 20 | } 21 | .patient-details a { 22 | font-size: 16px; 23 | font-family: $OpenSansBoldFont; 24 | text-transform: capitalize; 25 | width: 22%; 26 | white-space: nowrap; 27 | overflow: hidden; 28 | text-overflow: ellipsis; 29 | text-align: right; 30 | background: $lightestGray; 31 | padding: 10px 15px; 32 | border-radius: 5px; 33 | box-shadow: 0px 4px 5px -2px $lightGray; 34 | border: 1px solid $lightGray; 35 | &:hover { 36 | text-decoration: none; 37 | } 38 | @media screen and (max-width: 768px) { 39 | display: none; 40 | } 41 | } 42 | 43 | .reg-header-right{ 44 | width:auto; 45 | } 46 | -------------------------------------------------------------------------------- /src/controllers/appointmentsHeaderController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('bahmni.appointments') 4 | .controller('AppointmentsHeaderController', ['$scope', '$state', 'appService', 5 | function ($scope, $state, appService) { 6 | var setBackLinks = function () { 7 | var backLinks = [{label: "Home", url: Bahmni.Appointments.Constants.homeUrl, accessKey: "h", icon: "fa-home"}]; 8 | 9 | // TODO:permissions for admin 10 | backLinks.push({text: "APPOINTMENTS_MANAGE", state: "home.manage", accessKey: "M"}); 11 | var enableAdminPage = appService.getAppDescriptor().getExtensionById('bahmni.appointments.admin', true); 12 | if (enableAdminPage) { 13 | backLinks.push({text: "APPOINTMENTS_ADMIN", state: "home.admin.service", accessKey: "A", requiredPrivilege: Bahmni.Appointments.Constants.privilegeForAdmin}); 14 | } 15 | $state.get('home').data.backLinks = backLinks; 16 | }; 17 | var init = function () { 18 | setBackLinks(); 19 | }; 20 | return init(); 21 | }]); 22 | -------------------------------------------------------------------------------- /ui/react-components/components/ColorPicker/ColorPicker.module.scss: -------------------------------------------------------------------------------- 1 | .colorPickerWrapper { 2 | position: relative; 3 | display: inline-block; 4 | vertical-align: middle; 5 | margin: 0; 6 | .colorBoxTrigger { 7 | margin: 0; 8 | overflow: hidden; 9 | padding: 3px; 10 | border: 1px solid #ddd; 11 | border-radius: 3px; 12 | .selectedColorBox { 13 | height: 17px; 14 | width: 17px; 15 | display: inline-block; 16 | float: left; 17 | border: 1px solid transparent; 18 | } 19 | i { 20 | float: left; 21 | line-height: 19px; 22 | padding: 0 2px 0 5px; 23 | font-size: 17px; 24 | color: #1a1a1a; 25 | } 26 | } 27 | .colorBox { 28 | background: #fff; 29 | z-index: 90; 30 | width: 135px; 31 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); 32 | position: absolute; 33 | overflow: hidden; 34 | padding: 1px; 35 | top: 100%; 36 | left: 0; 37 | .colorTile { 38 | display: inline-block; 39 | padding: 0; 40 | float: left; 41 | margin: 1px; 42 | width: 25px; 43 | height: 25px; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ui/react-components/components/CancelConfirmation/CancelConfirmation.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .cancelModal { 4 | .cancelModalCloseIcon { 5 | text-align: right; 6 | button{ 7 | border: none; 8 | background: none; 9 | padding: 0; 10 | color: $secondary-color-2; 11 | } 12 | } 13 | > div:nth-child(2) { 14 | padding: 0 20px 20px; 15 | 16 | .cancelModalTitle { 17 | margin: 0 0 12px; 18 | font-size: 30px; 19 | line-height: normal; 20 | color: $secondary-color-2; 21 | } 22 | .cancelModalBody { 23 | margin: 0 0 24px; 24 | line-height: normal; 25 | } 26 | 27 | .button { 28 | background: #f2f2f2; 29 | height: 35px; 30 | border: 0; 31 | border-radius: 4px; 32 | padding: 0 20px; 33 | width: 85px; 34 | 35 | &:hover { 36 | background: darkgrey; 37 | } 38 | } 39 | 40 | .no { 41 | color: $secondary-color-1; 42 | background: $primary-color-2; 43 | margin-right: 24px; 44 | 45 | &:hover { 46 | background: $primary-color-2; 47 | opacity: 1; 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/directives/timeValidator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('bahmni.appointments') 4 | .directive('timeValidator', function () { 5 | var DateUtil = Bahmni.Common.Util.DateUtil; 6 | 7 | var isStartTimeBeforeEndTime = function (model) { 8 | if (!model.startTime || !model.endTime) { 9 | return true; 10 | } 11 | var timeFormat = 'THH:mm:ss'; 12 | var startTime = DateUtil.getDateTimeInSpecifiedFormat(model.startTime, timeFormat); 13 | var endTime = DateUtil.getDateTimeInSpecifiedFormat(model.endTime, timeFormat); 14 | return (startTime < endTime); 15 | }; 16 | 17 | return { 18 | restrict: 'A', 19 | require: 'ngModel', 20 | link: function (scope, element, attrs, ctrl) { 21 | function validate () { 22 | ctrl.$setValidity("timeSequence", isStartTimeBeforeEndTime(ctrl.$viewValue)); 23 | } 24 | scope.$watch(attrs.ngModel + '.startTime', validate); 25 | scope.$watch(attrs.ngModel + '.endTime', validate); 26 | } 27 | }; 28 | }); 29 | 30 | -------------------------------------------------------------------------------- /ui/react-components/components/AppointmentFilterWrapper/FilterWrapper.spec.js: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/extend-expect'; 2 | import {fireEvent, waitForElement} from "@testing-library/react"; 3 | import React from "react"; 4 | import {renderWithReactIntl} from '../../utils/TestUtil'; 5 | import FilterWrapper from './FilterWrapper'; 6 | 7 | describe('Filter Wrapper for Search Fields',()=>{ 8 | 9 | it('Privder Search rendered ',()=>{ 10 | const {getByText} = renderWithReactIntl() 11 | 12 | expect(getByText('Provider')).toBeInTheDocument() 13 | expect(getByText('Choose Provider')).toBeInTheDocument() 14 | 15 | }) 16 | 17 | it('Location Search rendered ',()=>{ 18 | const {getByLabelText,getAllByText} = renderWithReactIntl() 19 | 20 | expect(getAllByText('Location').length).toEqual(2) 21 | }) 22 | it('Appoitment Status Search rendered ',()=>{ 23 | const {getByText} = renderWithReactIntl() 24 | 25 | expect(getByText('Appointment Status')).toBeInTheDocument() 26 | expect(getByText('Enter Status Name')).toBeInTheDocument() 27 | 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /ui/react-components/mapper/patientMapper.spec.js: -------------------------------------------------------------------------------- 1 | import {getPatientName} from "./patientMapper"; 2 | 3 | describe('Patient Mapper', () => { 4 | it('should return full name joining givenName and familyName', () => { 5 | const actualResult = getPatientName({ 6 | givenName: 'givenName', 7 | familyName: 'familyName' 8 | }); 9 | 10 | expect(actualResult).toEqual('givenName familyName'); 11 | }); 12 | 13 | it('should return only given name when familyName is undefined', () => { 14 | const actualResult = getPatientName({ 15 | givenName: 'givenName' 16 | }); 17 | 18 | expect(actualResult).toEqual('givenName'); 19 | }); 20 | 21 | it('should return only familyName when given name is undefined', () => { 22 | const actualResult = getPatientName({ 23 | familyName: 'familyName' 24 | }); 25 | 26 | expect(actualResult).toEqual('familyName'); 27 | }); 28 | 29 | it('should return undefined when familyName and given name is undefined', () => { 30 | const actualResult = getPatientName({}); 31 | 32 | expect(actualResult).toEqual(""); 33 | }); 34 | }); -------------------------------------------------------------------------------- /ui/react-components/components/CustomPopup/CustomPopup.jsx: -------------------------------------------------------------------------------- 1 | import Popup from "reactjs-popup"; 2 | import React from "react"; 3 | import PropTypes from "prop-types"; 4 | import classNames from 'classnames'; 5 | 6 | const CustomPopup = props => { 7 | 8 | const {triggerComponent, popupContent, closeOnDocumentClick, closeOnEscape, open, style, onClose} = props; 9 | 10 | return ( 11 | 18 | { 19 | close => (React.cloneElement(popupContent, {close: close})) 20 | } 21 | 22 | ); 23 | }; 24 | 25 | CustomPopup.propTypes = { 26 | closeOnDocumentClick: PropTypes.bool, 27 | closeOnEscape: PropTypes.bool, 28 | open:PropTypes.bool, 29 | popupContent: PropTypes.object.isRequired, 30 | triggerComponent: PropTypes.object, 31 | style: PropTypes.string, 32 | onClose: PropTypes.func 33 | }; 34 | 35 | export default CustomPopup; 36 | -------------------------------------------------------------------------------- /ui/react-components/components/UpdateConfirmationModal/UpdateConfirmationModal.spec.jsx: -------------------------------------------------------------------------------- 1 | import UpdateConfirmationModal from "../UpdateConfirmationModal/UpdateConfirmationModal"; 2 | import React from "react"; 3 | import {fireEvent} from '@testing-library/react' 4 | import {renderWithReactIntl} from "../../utils/TestUtil"; 5 | import CancelConfirmation from "../CancelConfirmation/CancelConfirmation"; 6 | 7 | describe('Update Confirmation Modal ', () => { 8 | 9 | it('should render update confirm modal closeIcon, title, body, yes and no buttons', () => { 10 | const {getByText} = renderWithReactIntl(); 11 | getByText('Kindly Confirm'); 12 | getByText('This will update the details of the selected appointment.'); 13 | getByText('No, go back'); 14 | getByText('Yes, I confirm'); 15 | }); 16 | 17 | it('should call save function provided from context on click of yes button', () => { 18 | const saveSpy = jest.fn(); 19 | const {getByText} = renderWithReactIntl(); 20 | fireEvent.click(getByText('Yes, I confirm')); 21 | expect(saveSpy).toHaveBeenCalledTimes(1); 22 | }); 23 | 24 | }) 25 | -------------------------------------------------------------------------------- /ui/react-components/components/AppointmentType/AppointmentType.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | import {injectIntl} from "react-intl"; 4 | import {TELECONSULTATION_APPOINTMENT} from "../../constants"; 5 | import { Checkbox } from 'carbon-components-react'; 6 | 7 | 8 | 9 | const AppointmentType = props => { 10 | 11 | const {onChange, appointmentType, isTeleconsultation, isTeleconsultationDisabled } = props; 12 | 13 | const isVirtual = () => { 14 | return appointmentType === "Virtual" || isTeleconsultation; 15 | } 16 | 17 | return ( 18 |
19 | 26 |
) 27 | }; 28 | 29 | AppointmentType.propTypes = { 30 | onChange: PropTypes.func, 31 | appointmentType: PropTypes.string, 32 | isTeleconsultation: PropTypes.bool, 33 | isTeleconsultationDisabled: PropTypes.bool 34 | }; 35 | 36 | export default injectIntl(AppointmentType); -------------------------------------------------------------------------------- /ui/react-components/components/ErrorMessage/ErrorMessage.spec.jsx: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/extend-expect'; 2 | import {render} from "@testing-library/react"; 3 | import ErrorMessage from "./ErrorMessage.jsx"; 4 | import React from "react"; 5 | 6 | jest.mock('../../utils/CookieUtil'); 7 | 8 | describe('ErrorMessage', () => { 9 | 10 | it('should render the component without prop', () => { 11 | const {container} = render(); 12 | expect(container.querySelector('.messageHolder')).not.toBeNull(); 13 | }); 14 | 15 | it('should render the component even when message is null', () => { 16 | const {container} = render(); 17 | expect(container.querySelector('.messageHolder')).not.toBeNull(); 18 | }); 19 | 20 | it('should render the component with empty message', () => { 21 | const {container} = render(); 22 | expect(container.querySelector('.messageHolder')).not.toBeNull(); 23 | }); 24 | 25 | it('should render the component with given message', () => { 26 | const {getByText} = render(); 27 | getByText("Error message"); 28 | }); 29 | 30 | }); 31 | 32 | -------------------------------------------------------------------------------- /ui/react-components/components/UpdateConfirmationModal/UpdateConfirmationModal.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../variables.scss'; 2 | 3 | .updateConfirmationModal { 4 | .updateConfirmationModalCloseIcon { 5 | text-align: right; 6 | button{ 7 | border: none; 8 | background: none; 9 | color: $secondary-color-2; 10 | cursor: pointer; 11 | padding: 0; 12 | } 13 | } 14 | > div:nth-child(2) { 15 | padding: 0 20px 20px; 16 | 17 | .updateConfirmationModalTitle { 18 | margin: 0 0 12px; 19 | font-size: 30px; 20 | line-height: normal; 21 | color: $secondary-color-2; 22 | } 23 | .updateConfirmationModalBody { 24 | margin: 0 0 24px; 25 | line-height: normal; 26 | } 27 | 28 | .button { 29 | background: #f2f2f2; 30 | height: 35px; 31 | border: 0; 32 | border-radius: 4px; 33 | padding: 0 20px; 34 | 35 | &:hover { 36 | background: darkgrey; 37 | } 38 | } 39 | 40 | .no { 41 | color: $secondary-color-1; 42 | background: $primary-color-2; 43 | margin-right: 24px; 44 | 45 | &:hover { 46 | background: $primary-color-2; 47 | opacity: 1; 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ui/react-components/components/Tags/Tags.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import classNames from "classnames"; 3 | import { newTag, tagHolder, disable,customTagHolder} from './Tags.module.scss' 4 | import './Tags.module.scss' 5 | import {map} from 'lodash'; 6 | import PropTypes from "prop-types"; 7 | import { Tag } from 'carbon-components-react'; 8 | 9 | const Tags = (props) => { 10 | 11 | const {selectedTags, onChange, isDisabled, style=''} = props; 12 | 13 | const removeTag = (tag) => onChange(tag.value); 14 | 15 | return ( 16 | selectedTags && selectedTags.length > 0 ? (
17 | { 18 | map(selectedTags, (tagItem, index) => ( 19 |
20 | {tagItem.label} 21 |
)) 22 | } 23 |
) : null) 24 | }; 25 | 26 | Tags.propTypes = { 27 | onChange: PropTypes.func.isRequired, 28 | selectedTags: PropTypes.array, 29 | isDisabled: PropTypes.bool 30 | }; 31 | 32 | export default Tags; 33 | 34 | -------------------------------------------------------------------------------- /ui/react-components/components/AppointmentNotes/AppointmentNotes.jsx: -------------------------------------------------------------------------------- 1 | import React, {useEffect, useState} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import {injectIntl} from "react-intl"; 4 | import { TextArea } from 'carbon-components-react' 5 | 6 | const AppointmentNotes = (props) => { 7 | const {intl, onChange, value} = props; 8 | const placeHolder = intl.formatMessage({ 9 | id: 'PLACEHOLDER_APPOINTMENT_NOTES_MAX_LENGTH', defaultMessage: 'Maximum of 250 characters' 10 | }); 11 | const [notes, setNotes] = useState(value); 12 | useEffect(()=>{ 13 | setNotes(value); 14 | }, [value]) 15 | const handleChange = props => { 16 | setNotes(props.target.value) 17 | } 18 | return (
19 |