Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config UI - add custom timepicker field for submit by #8

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/common-ui/src/components/app-shell/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export const AppShell = ({
navLinks,
AuthComponent
}: AppShellProps) => {
const userName = localStorage.getItem('user_name')
? localStorage.getItem('user_name')
const userName = getLoggedInUserInfo()
? getLoggedInUserInfo()['given_name']
: ''
const [user, setUser] = React.useState<User>({ name: userName })
const [token, setToken] = useState(localStorage.getItem('token'))
Expand Down
2 changes: 2 additions & 0 deletions modules/config-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"framer-motion": "^6",
"i18next": "^21.6.14",
"react": "^18.1.0",
"react-datepicker": "^4.8.0",
"react-dom": "^18.1.0",
"react-i18next": "^11.16.9",
"react-icons": "^4.3.1",
Expand All @@ -43,6 +44,7 @@
"@storybook/preset-create-react-app": "^4.1.0",
"@storybook/react": "^6.4.22",
"@storybook/testing-library": "^0.0.11",
"@types/react-datepicker": "^4.4.2",
"craco-module-federation": "^1.1.0",
"external-remotes-plugin": "^1.0.0",
"prettier": "^2.5.1",
Expand Down
51 changes: 51 additions & 0 deletions modules/config-ui/rjsf-custom-field.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
1. add dependecy to config-ui package

```
yarn workspace config-ui add react-datepicker

yarn workspace config-ui add @types/react-datepicker -D
```

2. copy components folder to `modules/config-ui/src`

3. in ConfigEditorPage provides widgets to form

```
const widgets = {
"time": TimePickerWidget
};
...
<Form
id="cForm"
// @ts-ignore
ref={(form) => {
configForms.push(form);
}}
widgets={widgets} // provides custom widgets
onSubmit={onSubmit}
...
```

4. in json config configure this custom widgets to be used with submit_by field

add field

```
...


"submit_by1": {
"title": "Submit by 1",
"type": "string"
},
...


"uischema": {
"class_attendance":{
"submit_by1":{
"ui:widget": "time"
}
}
}
```
43 changes: 43 additions & 0 deletions modules/config-ui/src/components/chakra-ui/TimePicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Reference
* https://gist.github.com/baumandm/8665a34bc418574737847f7394f98bd9#file-date-picker-tsx
* https://reactdatepicker.com/#example-select-time-only
* https://github.com/Hacker0x01/react-datepicker/
* https://gist.github.com/igoro00/99e9d244677ccafbf39667c24b5b35ed#file-date-picker-css
*/
import React, { HTMLAttributes } from "react";
import ReactDatePicker from "react-datepicker";

import "react-datepicker/dist/react-datepicker.css";
import "./time-picker.css";

interface Props {
isClearable?: boolean;
onChange: (date: Date) => any;
selectedDate: Date | undefined;
showPopperArrow?: boolean;
}

const DatePicker = ({
selectedDate,
onChange,
isClearable = false,
showPopperArrow = false,
...props
}: Props & HTMLAttributes<HTMLElement>) => {
return (
<ReactDatePicker
selected={selectedDate}
onChange={onChange}
isClearable={isClearable}
showPopperArrow={showPopperArrow}
showTimeSelect
showTimeSelectOnly
timeIntervals={15}
timeCaption="Time"
dateFormat="h:mm aa"
/>
);
};

export default DatePicker;
134 changes: 134 additions & 0 deletions modules/config-ui/src/components/chakra-ui/time-picker.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
.react-datepicker {
font-family: unset;
font-size: 0.9rem;
}

.react-datepicker-wrapper,
.react-datepicker__input-container {
display: block;
}

.react-datepicker__input-container {
font-size: 1rem;
padding-left: 1rem;
padding-right: 1rem;
height: 2.5rem;
border-radius: 0.25rem;
border: 1px solid;
border-color: hsl(0, 0%, 80%);
}

.react-datepicker__input-container:hover {
border-color: hsl(0, 0%, 70%);
}
.react-datepicker__input-container:focus-within {
z-index: 1;
border-color: #3182ce;
box-shadow: 0 0 0 1px #3182ce;
}

.react-datepicker__input-container > input {
width: 100%;
height: 100%;
outline: 0;
}

.react-datepicker__navigation--next--with-time:not(.react-datepicker__navigation--next--with-today-button) {
right: 90px;
}

.react-datepicker__navigation--previous,
.react-datepicker__navigation--next {
height: 8px;
}

.react-datepicker__navigation--previous {
border-right-color: #cbd5e0;
}

.react-datepicker__navigation--previous:hover {
border-right-color: #a0aec0;
}

.react-datepicker__navigation--next {
border-left-color: #cbd5e0;
}

.react-datepicker__navigation--next:hover {
border-left-color: #a0aec0;
}

.react-datepicker__header {
background: #f7fafc;
}

.react-datepicker__header,
.react-datepicker__time-container {
border-color: #e2e8f0;
}

.react-datepicker__current-month,
.react-datepicker-time__header,
.react-datepicker-year-header {
font-size: inherit;
font-weight: 600;
}

.react-datepicker__time-container
.react-datepicker__time
.react-datepicker__time-box
ul.react-datepicker__time-list
li.react-datepicker__time-list-item {
margin: 0 1px 0 0;
height: auto;
padding: 7px 10px;
}

.react-datepicker__time-container
.react-datepicker__time
.react-datepicker__time-box
ul.react-datepicker__time-list
li.react-datepicker__time-list-item:hover {
background: #edf2f7;
}

.react-datepicker__day:hover {
background: #edf2f7;
}

.react-datepicker__day--selected,
.react-datepicker__day--in-selecting-range,
.react-datepicker__day--in-range,
.react-datepicker__month-text--selected,
.react-datepicker__month-text--in-selecting-range,
.react-datepicker__month-text--in-range,
.react-datepicker__time-container
.react-datepicker__time
.react-datepicker__time-box
ul.react-datepicker__time-list
li.react-datepicker__time-list-item--selected {
background: #3182ce;
font-weight: normal;
}

.react-datepicker__time-container
.react-datepicker__time
.react-datepicker__time-box
ul.react-datepicker__time-list
li.react-datepicker__time-list-item--selected:hover {
background: #2a69ac;
}

.react-datepicker__close-icon::after {
background-color: unset;
border-radius: unset;
font-size: 1.5rem;
font-weight: bold;
color: hsl(0, 0%, 80%);
height: 20px;
width: 20px;
}

.react-datepicker__close-icon::after:hover {
color: hsl(0, 0%, 70%);
}
45 changes: 45 additions & 0 deletions modules/config-ui/src/components/rjsf-widgets/TimePickerWidget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useState } from "react";
import DatePicker from "../chakra-ui/TimePicker";

const parseTime = (timeString: string): Date | undefined => {
if (timeString == "" || timeString == undefined) return undefined;

var time = timeString.match(/(\d+)(:(\d\d))?\s*(p?)/i);
if (time == null) return undefined;

var hours = parseInt(time[1], 10);
if (hours == 12 && !time[4]) {
hours = 0;
} else {
hours += hours < 12 && time[4] ? 12 : 0;
}
var d = new Date();
d.setHours(hours);
d.setMinutes(parseInt(time[3], 10) || 0);
d.setSeconds(0, 0);
return d;
};

const formatTime = (date: Date): string => {
const hr = date.getHours();
const min = date.getMinutes();
return (
"" + (hr > 12 ? hr - 12 : hr) + ":" + min + " " + (hr > 12 ? "PM" : "AM")
);
};

const TimePickerWidget = (props: any) => {
const [value, setValue] = useState(parseTime(props.value));
return (
<DatePicker
id="date"
selectedDate={value}
onChange={(date) => {
props.onChange(formatTime(date as Date));
setValue(date as Date);
}}
/>
);
};

export default TimePickerWidget;
6 changes: 6 additions & 0 deletions modules/config-ui/src/pages/config-view/ConfigEditorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
fetchConfigSchema,
saveConfigData,
} from "../../services/ConfigService";
import TimePickerWidget from "../../components/rjsf-widgets/TimePickerWidget";

const ObjectFieldTemplate = (props: any) => {
return (
Expand Down Expand Up @@ -219,6 +220,10 @@ const ConfigEditor = ({ moduleId }: any) => {
return;
};

const widgets = {
time: TimePickerWidget,
};

return (
<Box marginX={4}>
<Flex direction={"row"}>
Expand Down Expand Up @@ -270,6 +275,7 @@ const ConfigEditor = ({ moduleId }: any) => {
ref={(form) => {
configForms.push(form);
}}
widgets={widgets}
onSubmit={onSubmit}
schema={section.schema}
uiSchema={section.uischema}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@
},
"uniqueItems": true
},
"submit_by1": {
"title": "Submit by 1",
"type": "string"
},
"previous_attendance_edit": {
"title": "Enabling if editing previous attendance is allowed",
"type": "boolean",
Expand Down Expand Up @@ -112,7 +116,13 @@
}
}
},
"uischema": {}
"uischema": {
"class_attendance": {
"submit_by1": {
"ui:widget": "time"
}
}
}
},
{
"name": "report",
Expand Down
Loading