diff --git a/src/main/webapp/app/_bootstrap-variables.scss b/src/main/webapp/app/_bootstrap-variables.scss index eaf13959..063eb76a 100644 --- a/src/main/webapp/app/_bootstrap-variables.scss +++ b/src/main/webapp/app/_bootstrap-variables.scss @@ -15,5 +15,10 @@ $theme-colors: ( 'action': #1db2a1, 'cancel': #dd5959, 'expense': #c21717, - 'income': #0e516d + 'income': #0e516d, + 'bimu': #7cc250, + 'jinlong': #b78cfb, + 'qicai': #71ccff, + 'nemo': #ff9e3c, + 'peacock': #ff7d7d, ); diff --git a/src/main/webapp/app/config/icon-loader.ts b/src/main/webapp/app/config/icon-loader.ts index 6f301254..6d0a98a5 100644 --- a/src/main/webapp/app/config/icon-loader.ts +++ b/src/main/webapp/app/config/icon-loader.ts @@ -50,6 +50,7 @@ import { faWhatsappSquare } from '@fortawesome/free-brands-svg-icons/faWhatsappS import { library } from '@fortawesome/fontawesome-svg-core'; import { faSortAmountUp } from '@fortawesome/free-solid-svg-icons/faSortAmountUp'; import { faEuroSign } from '@fortawesome/free-solid-svg-icons/faEuroSign'; +import { faFilter } from '@fortawesome/free-solid-svg-icons/faFilter'; import { faTimes } from '@fortawesome/free-solid-svg-icons'; export const loadIcons = () => { @@ -104,6 +105,7 @@ export const loadIcons = () => { faSortAmountUp, faPlaneDeparture, faEuroSign, - faFish + faFish, + faFilter ); }; diff --git a/src/main/webapp/app/entities/club-family/family-member-create.tsx b/src/main/webapp/app/entities/club-family/family-member-create.tsx index 575978f5..094a2e91 100644 --- a/src/main/webapp/app/entities/club-family/family-member-create.tsx +++ b/src/main/webapp/app/entities/club-family/family-member-create.tsx @@ -6,16 +6,30 @@ import { AvForm, AvGroup, AvInput, AvField } from 'availity-reactstrap-validatio import { Translate, translate } from 'react-jhipster'; import { connect } from 'react-redux'; import { getUsersWithoutFamily } from 'app/modules/administration/user-management/user-management.reducer'; -import { createEntity, reset } from 'app/entities/user-cc-info/user-cc-info.reducer'; +import { getEntity, createEntity, updateEntity, deleteEntity, reset } from 'app/entities/user-cc-info/user-cc-info.reducer'; import { IRootState } from 'app/shared/reducers'; import { IUser } from 'app/shared/model/user.model'; import { concatFullName } from 'app/shared/util/string-util'; +import { IRedirectLocationState } from 'app/shared/auth/app-route'; -export interface IFamilyMemberCreateProps extends StateProps, DispatchProps, RouteComponentProps<{ id: string }> {} +export interface IFamilyMemberCreateProps + extends StateProps, + DispatchProps, + RouteComponentProps<{ id: string; familyCode: string }, any, IRedirectLocationState> {} -class FamilyMemberCreate extends React.Component { +export interface IFamilyMemberState { + isNew: boolean; + hasFamilyCode: boolean; +} +export class FamilyMemberCreate extends React.Component { constructor(props: IFamilyMemberCreateProps) { super(props); + this.state = { + isNew: !!this.props.match.params.familyCode && !this.props.match.params.id, + hasFamilyCode: !!this.props.match.params.familyCode || !!this.props.match.params.id, + }; + this.renderNames = this.renderNames.bind(this); + this.setFamilyCode = this.setFamilyCode.bind(this); } componentWillUpdate(nextProps: IFamilyMemberCreateProps) { @@ -24,25 +38,45 @@ class FamilyMemberCreate extends React.Component { } } - handleClose = () => { - this.props.history.push(`/entity/members/club-family/${this.props.match.params.id}`); - }; - componentDidMount() { - this.props.reset(); - this.props.getUsersWithoutFamily(); + if (this.state.isNew) { + this.props.reset(); + this.props.getUsersWithoutFamily(); + } else { + this.props.getEntity(this.props.match.params.id); + } } renderNames(users: readonly IUser[]): ReactNode { - return users.map((user: IUser) => { - if (user) { - return ( - - ); - } - }); + return users && users.length <= 0 ? ( + + ) : ( + users.map((user: IUser) => { + if (user) { + return ( + + ); + } + }) + ); + } + + handleClose = () => { + this.props.history.push(`${this.props.location.state?.from}` ?? '/entity/members/cc-family'); + }; + + setFamilyCode(event: { target: HTMLInputElement }): void { + if (event.target.value === '') { + this.setState({ + hasFamilyCode: false, + }); + } else { + this.setState({ + hasFamilyCode: true, + }); + } } saveEntity = (event: any, errors: any, values: any) => { @@ -50,80 +84,118 @@ class FamilyMemberCreate extends React.Component { if (values.familyRole === 'MEMBER') { values.familyRole = null; } - const { userEntity } = this.props; const entity = { ...userEntity, ...values, }; - - this.props.createEntity(entity); + if (this.state.isNew) { + this.props.createEntity(entity); + } else { + if (entity.clubFamilyCode === '') { + this.props.deleteEntity(entity.id); + } else { + this.props.updateEntity(entity); + } + } } }; render() { - const { users } = this.props; - const { id: familyCode } = this.props.match.params; + const { location, users, userEntity, loading } = this.props; + const { familyCode } = this.props.match.params; + const { isNew, hasFamilyCode } = this.state; return (
-

- Add Family Member -

+ {isNew ? ( +

+ Add CC Family Member +

+ ) : ( +

+ Edit CC Family Member +

+ )}
- - - - - - {this.renderNames(users)} - - - - - - - - - - - - - - - - - - - - -
- -   - -
-
+ {loading ? ( +

Loading...

+ ) : ( + + + + + + + {isNew ? ( + this.renderNames(users) + ) : ( + + )} + + + + + + {isNew ? null : } + + + + + + + + {hasFamilyCode ? ( + + + + + + + + + ) : null} +
+ +   + +
+
+ )}
@@ -134,14 +206,18 @@ class FamilyMemberCreate extends React.Component { // Reducer props const mapStateToProps = (storeState: IRootState) => ({ users: storeState.userManagement.users, + loading: storeState.userCCInfo.loading, userEntity: storeState.userCCInfo.entity, updateSuccess: storeState.userCCInfo.updateSuccess, }); // Reducer Action Creators const mapDispatchToProps = { + getEntity, getUsersWithoutFamily, createEntity, + updateEntity, + deleteEntity, reset, }; diff --git a/src/main/webapp/app/entities/club-family/family-member.scss b/src/main/webapp/app/entities/club-family/family-member.scss new file mode 100644 index 00000000..ea493a01 --- /dev/null +++ b/src/main/webapp/app/entities/club-family/family-member.scss @@ -0,0 +1,25 @@ +.search-bar-prepend span { + background-color: white; + border-right: none; +} + +.search-bar-input { + border-left: none; + border-right: none; +} + +.search-bar-append { + background-color: white; + border-left: none; + border-color: #ced4da; +} + +.search-bar-append:focus { + background-color: white; +} + +.member-card { + padding: 1rem 0.5rem 1rem 1rem; + margin-top: 1rem; + margin-bottom: 1rem; +} diff --git a/src/main/webapp/app/entities/club-family/family-member.tsx b/src/main/webapp/app/entities/club-family/family-member.tsx new file mode 100644 index 00000000..264e46a2 --- /dev/null +++ b/src/main/webapp/app/entities/club-family/family-member.tsx @@ -0,0 +1,131 @@ +import './family-member.scss'; +import React from 'react'; +import { Link, RouteComponentProps } from 'react-router-dom'; +import { Button, Row, Col, InputGroupAddon, InputGroup, Input } from 'reactstrap'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Translate, translate } from 'react-jhipster'; +import { connect } from 'react-redux'; +import { IRootState } from 'app/shared/reducers'; + +import AuthorizationChecker from 'app/shared/components/authorization-checker/authorization-checker'; +import CCRole from 'app/shared/model/enum/cc-role.enum'; +import EventRole from 'app/shared/model/enum/event-role.enum'; +import MemberCard from './member-card'; +import FilterSearchBar from 'app/shared/components/advancedSearchModal/advancedSearchModal'; +import EventModal from 'app/shared/components/eventModal/event-modal'; + +import { getUsersWithFilter, reset as resetUsers } from 'app/entities/user-cc-info/user-cc-info.reducer'; +import { getClubFamilyDetails } from 'app/shared/services/club-family-info.service'; +import { reset as resetFilter } from 'app/shared/components/advancedSearchModal/advancedSearchModal.reducer'; + +export interface IFamilyMemberProps extends StateProps, DispatchProps, RouteComponentProps<{ familyCode: string }> {} + +export interface IFamilyMemberState { + searchModalIsOpen: boolean; +} +class FamilyMember extends React.Component { + constructor(props: IFamilyMemberProps) { + super(props); + this.state = { + searchModalIsOpen: false, + }; + } + + async componentDidMount() { + this.props.getUsersWithFilter(this.props.match.params.familyCode); + } + + componentWillUnmount() { + this.props.resetFilter(); + this.props.resetUsers(); + } + + showSearchModal = (): void => { + this.setState({ + searchModalIsOpen: true, + }); + }; + + toggleSearchModal = (): void => { + this.setState({ + searchModalIsOpen: !this.state.searchModalIsOpen, + }); + }; + + onEditButtonClick = (userCCInfoId?: number): void => {}; + + render() { + const { users, match } = this.props; + const { searchModalIsOpen } = this.state; + const familyName = getClubFamilyDetails(match.params.familyCode).name; + return ( +
+ +

+ {familyName ? translate(familyName) : null} +

+
+ + + Add + + + + + {/* ADD IN SEARCH ONCLICK TO THE BUTTON BELOW*/} + + + + + + + + {users && users.length > 0 ? ( +
+ {users.map(user => ( + + ))} +
+ ) : ( +
+ No CC Family Member found +
+ )} +
+
+ ); + } +} + +const mapStateToProps = ({ userCCInfo }: IRootState) => ({ + users: userCCInfo.entities, + selectedYearSessionFilter: userCCInfo.selectedYearSessionFilter, + yearSessionOptions: userCCInfo.yearSessionOptions, +}); + +const mapDispatchToProps = { + getUsersWithFilter, + resetFilter, + resetUsers, +}; + +type StateProps = ReturnType; +type DispatchProps = typeof mapDispatchToProps; + +export default connect(mapStateToProps, mapDispatchToProps)(FamilyMember); diff --git a/src/main/webapp/app/entities/club-family/index.tsx b/src/main/webapp/app/entities/club-family/index.tsx index fd0dfada..b9860196 100644 --- a/src/main/webapp/app/entities/club-family/index.tsx +++ b/src/main/webapp/app/entities/club-family/index.tsx @@ -6,12 +6,14 @@ import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route'; import ClubFamily from './club-family'; import ClubFamilyDetail from './club-family-detail'; import FamilyMemberCreate from './family-member-create'; +import FamilyMember from './family-member'; const Routes: React.FC = ({ match }) => ( <> - - + + + diff --git a/src/main/webapp/app/entities/club-family/member-card.tsx b/src/main/webapp/app/entities/club-family/member-card.tsx new file mode 100644 index 00000000..68051d30 --- /dev/null +++ b/src/main/webapp/app/entities/club-family/member-card.tsx @@ -0,0 +1,42 @@ +import 'app/styles/custom.scss'; +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Row, Col, Card, CardImg, Button } from 'reactstrap'; +// tslint:disable-next-line:no-unused-variable +import { Translate, TextFormat } from 'react-jhipster'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import AuthorizationChecker from 'app/shared/components/authorization-checker/authorization-checker'; +import CCRole from 'app/shared/model/enum/cc-role.enum'; +import EventRole from 'app/shared/model/enum/event-role.enum'; +import { concatFullName } from 'app/shared/util/string-util'; + +import { IUserCCInfo } from 'app/shared/model/user-cc-info.model'; + +export interface IMemberCardProps { + userCCInfo: IUserCCInfo; + editPath: {}; +} + +const MemberCard: React.FC = ({ userCCInfo, editPath }) => ( + + + +
+ +
+ + +
{concatFullName(userCCInfo.user?.firstName, userCCInfo.user?.lastName)}
+

{userCCInfo.familyRole ?? 'Member'}

+ + + + +
+
+); + +export default MemberCard; diff --git a/src/main/webapp/app/entities/user-cc-info/user-cc-info.reducer.ts b/src/main/webapp/app/entities/user-cc-info/user-cc-info.reducer.ts index 46ea2264..7fe41d9a 100644 --- a/src/main/webapp/app/entities/user-cc-info/user-cc-info.reducer.ts +++ b/src/main/webapp/app/entities/user-cc-info/user-cc-info.reducer.ts @@ -1,11 +1,12 @@ import axios, { AxiosError } from 'axios'; import { ICrudGetAction, ICrudGetAllAction, ICrudPutAction, ICrudDeleteAction } from 'react-jhipster'; +import { AnyAction } from 'redux'; import { cleanEntity } from 'app/shared/util/entity-utils'; import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util'; import { IUserCCInfo, defaultValue } from 'app/shared/model/user-cc-info.model'; -import { AnyAction } from 'redux'; +import { IGetUsersWithFilters } from 'app/shared/type/custom-action'; export const ACTION_TYPES = { FETCH_USERCCINFO_LIST: 'userCCInfo/FETCH_USERCCINFO_LIST', @@ -13,6 +14,8 @@ export const ACTION_TYPES = { CREATE_USERCCINFO: 'userCCInfo/CREATE_USERCCINFO', UPDATE_USERCCINFO: 'userCCInfo/UPDATE_USERCCINFO', DELETE_USERCCINFO: 'userCCInfo/DELETE_USERCCINFO', + FETCH_YEAR_SESSION_OPTIONS: 'FETCH_YEAR_SESSION_OPTIONS', + SET_SELECTED_YEAR_SESSION_FILTER: 'SET_SELECTED_YEAR_SESSION_FILTER', RESET: 'userCCInfo/RESET', }; @@ -23,6 +26,8 @@ const initialState: IUserCCInfoState = { entity: defaultValue, updating: false, updateSuccess: false, + yearSessionOptions: [], + selectedYearSessionFilter: '', }; export interface IUserCCInfoState { @@ -32,6 +37,8 @@ export interface IUserCCInfoState { entity: Readonly; updating: boolean; updateSuccess: boolean; + yearSessionOptions: string[]; + selectedYearSessionFilter: string; } // Reducer @@ -40,6 +47,7 @@ export default (state: IUserCCInfoState = initialState, action: AnyAction): IUse switch (action.type) { case REQUEST(ACTION_TYPES.FETCH_USERCCINFO_LIST): case REQUEST(ACTION_TYPES.FETCH_USERCCINFO): + case REQUEST(ACTION_TYPES.FETCH_YEAR_SESSION_OPTIONS): return { ...state, errResponse: null, @@ -60,6 +68,7 @@ export default (state: IUserCCInfoState = initialState, action: AnyAction): IUse case FAILURE(ACTION_TYPES.CREATE_USERCCINFO): case FAILURE(ACTION_TYPES.UPDATE_USERCCINFO): case FAILURE(ACTION_TYPES.DELETE_USERCCINFO): + case FAILURE(ACTION_TYPES.FETCH_YEAR_SESSION_OPTIONS): return { ...state, loading: false, @@ -94,6 +103,19 @@ export default (state: IUserCCInfoState = initialState, action: AnyAction): IUse updateSuccess: true, entity: {}, }; + case SUCCESS(ACTION_TYPES.FETCH_YEAR_SESSION_OPTIONS): + return { + ...state, + loading: false, + yearSessionOptions: action.payload.data, + selectedYearSessionFilter: action.payload.data[0], + }; + case ACTION_TYPES.SET_SELECTED_YEAR_SESSION_FILTER: + const { selectedYearSession } = action.payload; + return { + ...state, + selectedYearSessionFilter: selectedYearSession, + }; case ACTION_TYPES.RESET: return { ...initialState, @@ -125,12 +147,42 @@ export const getUsersWithoutFamily: ICrudGetAllAction = (page, size payload: axios.get(`${apiUrl}?clubFamilyCode.specified=false`), }); +export const getUsersWithFamilyCode: IGetUsersWithFilters = (familyCode: string, yearSession?: string) => { + let requestUrl = `${apiUrl}?clubFamilyCode.equals=${familyCode}`; + if (yearSession) { + requestUrl = `${requestUrl}&yearSession.equals=${yearSession}`; + } + return { + type: ACTION_TYPES.FETCH_USERCCINFO_LIST, + payload: axios.get(requestUrl), + }; +}; + +export const getUsersWithFilter: any = (familyCode?: string, filters?: any) => { + let requestUrl = apiUrl; + + if (familyCode) { + requestUrl = `${apiUrl}?clubFamilyCode.equals=${familyCode}`; + } + if (filters) { + for (const filter in filters) { + if (filters[filter]) { + requestUrl = `${requestUrl}&${filter}.equals=${filters[filter]}`; + } + } + } + + return { + type: ACTION_TYPES.FETCH_USERCCINFO_LIST, + payload: axios.get(requestUrl), + }; +}; + export const createEntity: ICrudPutAction = entity => async dispatch => { const result = await dispatch({ type: ACTION_TYPES.CREATE_USERCCINFO, payload: axios.post(apiUrl, cleanEntity(entity)), }); - dispatch(getEntities()); return result; }; @@ -139,7 +191,6 @@ export const updateEntity: ICrudPutAction = entity => async dispatc type: ACTION_TYPES.UPDATE_USERCCINFO, payload: axios.put(apiUrl, cleanEntity(entity)), }); - dispatch(getEntities()); return result; }; @@ -149,10 +200,23 @@ export const deleteEntity: ICrudDeleteAction = id => async dispatch type: ACTION_TYPES.DELETE_USERCCINFO, payload: axios.delete(requestUrl), }); - dispatch(getEntities()); return result; }; +export const getYearSessionOptions: ICrudGetAllAction = (page, size, sort) => ({ + type: ACTION_TYPES.FETCH_YEAR_SESSION_OPTIONS, + payload: axios.get( + `api/year-sessions/values?cacheBuster=${new Date().getTime()}${sort ? `&page=${page}&size=${size}&sort=${sort}` : ''}` + ), +}); + +export const setSelectedYearSessionFilter = (selectedYearSession: string) => ({ + type: ACTION_TYPES.SET_SELECTED_YEAR_SESSION_FILTER, + payload: { + selectedYearSession, + }, +}); + export const reset = () => ({ type: ACTION_TYPES.RESET, }); diff --git a/src/main/webapp/app/entities/user-uni-info/user-uni-info.reducer.ts b/src/main/webapp/app/entities/user-uni-info/user-uni-info.reducer.ts index 383b1e03..506c5310 100644 --- a/src/main/webapp/app/entities/user-uni-info/user-uni-info.reducer.ts +++ b/src/main/webapp/app/entities/user-uni-info/user-uni-info.reducer.ts @@ -5,6 +5,7 @@ import { cleanEntity } from 'app/shared/util/entity-utils'; import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util'; import { IUserUniInfo, defaultValue } from 'app/shared/model/user-uni-info.model'; +import { ICourseProgram } from 'app/shared/model/course-program.model'; import { AnyAction } from 'redux'; export const ACTION_TYPES = { @@ -13,6 +14,7 @@ export const ACTION_TYPES = { CREATE_USERUNIINFO: 'userUniInfo/CREATE_USERUNIINFO', UPDATE_USERUNIINFO: 'userUniInfo/UPDATE_USERUNIINFO', DELETE_USERUNIINFO: 'userUniInfo/DELETE_USERUNIINFO', + FETCH_COURSE_PROGRAM_OPTIONS: 'FETCH_COURSE_PROGRAM_OPTIONS', RESET: 'userUniInfo/RESET', }; @@ -23,6 +25,8 @@ const initialState: IUserUniInfoState = { entity: defaultValue, updating: false, updateSuccess: false, + courseProgramOptions: [], + selectedCourseProgram: null, }; export interface IUserUniInfoState { @@ -32,6 +36,8 @@ export interface IUserUniInfoState { entity: Readonly; updating: boolean; updateSuccess: boolean; + courseProgramOptions: ICourseProgram[]; + selectedCourseProgram: null | ICourseProgram; } // Reducer @@ -40,6 +46,7 @@ export default (state: IUserUniInfoState = initialState, action: AnyAction): IUs switch (action.type) { case REQUEST(ACTION_TYPES.FETCH_USERUNIINFO_LIST): case REQUEST(ACTION_TYPES.FETCH_USERUNIINFO): + case REQUEST(ACTION_TYPES.FETCH_COURSE_PROGRAM_OPTIONS): return { ...state, errResponse: null, @@ -60,6 +67,7 @@ export default (state: IUserUniInfoState = initialState, action: AnyAction): IUs case FAILURE(ACTION_TYPES.CREATE_USERUNIINFO): case FAILURE(ACTION_TYPES.UPDATE_USERUNIINFO): case FAILURE(ACTION_TYPES.DELETE_USERUNIINFO): + case FAILURE(ACTION_TYPES.FETCH_COURSE_PROGRAM_OPTIONS): return { ...state, loading: false, @@ -94,6 +102,13 @@ export default (state: IUserUniInfoState = initialState, action: AnyAction): IUs updateSuccess: true, entity: {}, }; + case SUCCESS(ACTION_TYPES.FETCH_COURSE_PROGRAM_OPTIONS): + return { + ...state, + loading: false, + courseProgramOptions: action.payload.data, + selectedCourseProgram: action.payload.data[0], + }; case ACTION_TYPES.RESET: return { ...initialState, @@ -148,6 +163,11 @@ export const deleteEntity: ICrudDeleteAction = id => async dispatc return result; }; +export const getCourseProgramOptions: ICrudGetAllAction = (page, size, sort) => ({ + type: ACTION_TYPES.FETCH_COURSE_PROGRAM_OPTIONS, + payload: axios.get(`api/course-programs/faculty?sort=${sort}`), +}); + export const reset = () => ({ type: ACTION_TYPES.RESET, }); diff --git a/src/main/webapp/app/shared/components/advancedSearchModal/advancedSearchModal.reducer.ts b/src/main/webapp/app/shared/components/advancedSearchModal/advancedSearchModal.reducer.ts new file mode 100644 index 00000000..c0fd6bdc --- /dev/null +++ b/src/main/webapp/app/shared/components/advancedSearchModal/advancedSearchModal.reducer.ts @@ -0,0 +1,46 @@ +import { AnyAction } from 'redux'; + +export const ACTION_TYPES = { + SET_FILTER: 'filterSearchBa/SET_FILTER', + RESET: 'filterSearchBar/RESET', +}; + +const initialState = { + filters: null, +}; + +export interface IAdvancedSearchModalState { + filters: null | IFilter; +} + +export interface IFilter { + userFirstName?: string; + userLastName?: string; + courseProgramId?: number; + yearSession?: string; +} + +export default (state: IAdvancedSearchModalState = initialState, action: AnyAction): IAdvancedSearchModalState => { + switch (action.type) { + case ACTION_TYPES.SET_FILTER: + return { + ...state, + filters: action.payload, + }; + case ACTION_TYPES.RESET: + return { + ...initialState, + }; + default: + return state; + } +}; + +export const setEntity = (filters: IFilter) => ({ + type: ACTION_TYPES.SET_FILTER, + payload: filters, +}); + +export const reset = () => ({ + type: ACTION_TYPES.RESET, +}); diff --git a/src/main/webapp/app/shared/components/advancedSearchModal/advancedSearchModal.scss b/src/main/webapp/app/shared/components/advancedSearchModal/advancedSearchModal.scss new file mode 100644 index 00000000..3659a5f9 --- /dev/null +++ b/src/main/webapp/app/shared/components/advancedSearchModal/advancedSearchModal.scss @@ -0,0 +1,23 @@ +.filter-bar { + background-color: white; + border-color: #07ade1; + width: 100%; + padding: 0.5rem 0.75rem; + cursor: text; +} + +.filter-bar-text { + color: #07ade1; + font-size: 14px; + line-height: 16px; +} + +.advanced-search-modal { + width: 90%; + margin: auto; +} + +.family-button-group button { + width: 5.5rem; + font-weight: 500; +} diff --git a/src/main/webapp/app/shared/components/advancedSearchModal/advancedSearchModal.tsx b/src/main/webapp/app/shared/components/advancedSearchModal/advancedSearchModal.tsx new file mode 100644 index 00000000..c9fe1bda --- /dev/null +++ b/src/main/webapp/app/shared/components/advancedSearchModal/advancedSearchModal.tsx @@ -0,0 +1,150 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { Button, Modal, ModalHeader, ModalBody, Label, Input } from 'reactstrap'; +import { AvFeedback, AvForm, AvGroup, AvInput, AvField } from 'availity-reactstrap-validation'; +import { Translate } from 'react-jhipster'; +import { IRootState } from 'app/shared/reducers'; +import { getYearSessionOptions } from 'app/entities/user-cc-info/user-cc-info.reducer'; +import { getCourseProgramOptions } from 'app/entities/user-uni-info/user-uni-info.reducer'; +import { IFilter, setEntity } from './advancedSearchModal.reducer'; + +import './advancedSearchModal.scss'; + +interface IFilterSearchBarProps extends StateProps, DispatchProps { + isOpen: boolean; + toggleModal: () => void; + familyCode: string; + searchUsers: (familyCode: string, filters: any) => void; +} + +interface IAdvancedSearchModalState { + filters: IFilter; +} + +class AdvancedSearchModal extends React.Component { + constructor(props: IFilterSearchBarProps) { + super(props); + this.state = { + filters: { + userFirstName: '', + userLastName: '', + courseProgramId: undefined, + yearSession: '', + }, + }; + } + + componentDidUpdate(prevProps: IFilterSearchBarProps) { + if (this.props.isOpen !== prevProps.isOpen) { + this.props.getYearSessionOptions(0, 12, 'value,desc'); + this.props.getCourseProgramOptions(0, 12, 'value,desc'); + } + } + + renderYearSessionOptions = () => + this.props.yearSessionOptions.map(year => ( + + )); + + renderCourseProgramOptions = () => + this.props.courseProgramOptions.map(course => ( + + )); + + searchEntities = (event: any, errors: any, values: any) => { + if (errors.length === 0) { + const { familyCode, searchUsers, filters } = this.props; + const entity = { + ...filters, + ...values, + }; + this.props.setFilter(entity); + searchUsers(familyCode, entity); + this.props.toggleModal(); + } + }; + + render() { + const { isOpen, familyCode, toggleModal, filters } = this.props; + return ( + + + +

Advanced Search

+ + + + + + + + + + + {this.renderCourseProgramOptions()} + + + + + + {this.renderYearSessionOptions()} + + + {familyCode ? null : ( + +
CC Family
+
+ + + + + +
+
+ )} +
+ +   + +
+
+
+
+ ); + } +} + +const mapStateToProps = ({ userCCInfo, userUniInfo, advancedSearchModal }: IRootState) => ({ + yearSessionOptions: userCCInfo.yearSessionOptions, + courseProgramOptions: userUniInfo.courseProgramOptions, + filters: advancedSearchModal.filters, +}); + +const mapDispatchToProps = { + getYearSessionOptions, + getCourseProgramOptions, + setFilter: setEntity, +}; + +type StateProps = ReturnType; +type DispatchProps = typeof mapDispatchToProps; + +export default connect(mapStateToProps, mapDispatchToProps)(AdvancedSearchModal); diff --git a/src/main/webapp/app/shared/components/eventModal/event-modal.tsx b/src/main/webapp/app/shared/components/eventModal/event-modal.tsx index 5ef7dde8..aac332e7 100644 --- a/src/main/webapp/app/shared/components/eventModal/event-modal.tsx +++ b/src/main/webapp/app/shared/components/eventModal/event-modal.tsx @@ -8,10 +8,10 @@ import './event-modal.scss'; export interface IEventModalProps extends RouteComponentProps { isOpen: boolean; toggleModal: React.MouseEventHandler; - updatePath: string; - deletePath: string; - updateBtnAuthorizationProps: IAuthorizationCheckerOwnProps; - deleteBtnAuthorizationProps: IAuthorizationCheckerOwnProps; + updatePath?: string; + deletePath?: string; + updateBtnAuthorizationProps?: IAuthorizationCheckerOwnProps; + deleteBtnAuthorizationProps?: IAuthorizationCheckerOwnProps; } class EventModal extends React.Component { @@ -26,15 +26,19 @@ class EventModal extends React.Component {
- + {updatePath && ( + + )}
- + {deletePath && ( + + )}
diff --git a/src/main/webapp/app/shared/reducers/index.ts b/src/main/webapp/app/shared/reducers/index.ts index fc1b1683..f0cec1e8 100644 --- a/src/main/webapp/app/shared/reducers/index.ts +++ b/src/main/webapp/app/shared/reducers/index.ts @@ -69,7 +69,7 @@ import financeReport, { IFinanceReportState } from 'app/entities/finance-report/ import user, { IUserState } from 'app/modules/user-profile/user-profile.reducer'; - +import advancedSearchModal, { IAdvancedSearchModalState } from 'app/shared/components/advancedSearchModal/advancedSearchModal.reducer'; export interface IRootState { readonly authentication: IAuthenticationInitialState; readonly locale: LocaleState; @@ -94,6 +94,7 @@ export interface IRootState { /* jhipster-needle-add-reducer-type - JHipster will add reducer type here */ readonly loadingBar: any; readonly user: IUserState; + readonly advancedSearchModal: IAdvancedSearchModalState; } const rootReducer = combineReducers({ @@ -120,6 +121,7 @@ const rootReducer = combineReducers({ /* jhipster-needle-add-reducer-combine - JHipster will add reducer here */ loadingBar, user, + advancedSearchModal, }); export default rootReducer; diff --git a/src/main/webapp/app/shared/type/custom-action.ts b/src/main/webapp/app/shared/type/custom-action.ts index afd98e9b..d5d72aea 100644 --- a/src/main/webapp/app/shared/type/custom-action.ts +++ b/src/main/webapp/app/shared/type/custom-action.ts @@ -1,3 +1,5 @@ -import { IPayload } from 'react-jhipster'; +import { IPayload, IPayloadResult } from 'react-jhipster'; export declare type IGetEntityWithoutParams = () => IPayload | ((dispatch: any) => IPayload); + +export declare type IGetUsersWithFilters = (familyCode: string, filters?: any) => IPayload | IPayloadResult; diff --git a/src/main/webapp/app/styles/custom.scss b/src/main/webapp/app/styles/custom.scss index dc437360..f8a39e13 100644 --- a/src/main/webapp/app/styles/custom.scss +++ b/src/main/webapp/app/styles/custom.scss @@ -64,3 +64,13 @@ font-weight: 400; color: #7b7b7b; } + +.square-image { + position: relative; + padding-bottom: 100%; + overflow: hidden; +} + +.square-image img { + position: absolute; +} diff --git a/src/main/webapp/i18n/en/clubFamily.json b/src/main/webapp/i18n/en/clubFamily.json index d071560f..eb0ced70 100644 --- a/src/main/webapp/i18n/en/clubFamily.json +++ b/src/main/webapp/i18n/en/clubFamily.json @@ -3,21 +3,22 @@ "clubFamily": { "home": { "title": "CC Family", - "createLabel": "Create a new Club Family", - "createOrEditLabel": "Create or edit a Club Family", + "createLabel": "Create a new CC Family", + "createOrEditLabel": "Create or edit a CC Family", "notFound": "No CC Family found" }, "member": { "title": "CC Family Member", - "createLabel": "Add a new CC Family Member", + "createLabel": "Add new CC Family Member", + "editLabel": "Edit CC Family Member", "createOrEditLabel": "Add or edit a CC Family Member", "notFound": "No CC Family Member found" }, - "created": "A new Club Family is created with identifier {{ param }}", - "updated": "A Club Family is updated with identifier {{ param }}", - "deleted": "A Club Family is deleted with identifier {{ param }}", + "created": "A new CC Family is created with identifier {{ param }}", + "updated": "A CC Family is updated with identifier {{ param }}", + "deleted": "A CC Family is deleted with identifier {{ param }}", "delete": { - "question": "Are you sure you want to delete Club Family {{ id }}?" + "question": "Are you sure you want to delete CC Family {{ id }}?" }, "detail": { "title": "CC Family" @@ -51,7 +52,8 @@ "name": "Nemo", "slogan": "Nemo Nemo, No More Emo", "description": "Nemo Family Fishes always full with positive energy and make you away from Emo" - } + }, + "none": "None" } } } diff --git a/src/main/webapp/i18n/en/global.json b/src/main/webapp/i18n/en/global.json index 595033b7..70a93efa 100644 --- a/src/main/webapp/i18n/en/global.json +++ b/src/main/webapp/i18n/en/global.json @@ -166,7 +166,8 @@ "idexists": "A new {{ entityName }} cannot already have an ID", "noname": "A new {{ entityName }} cannot be created without a name", "idnull": "Invalid ID", - "noResultFound": "No result found" + "noResultFound": "No result found", + "noUserFound": "No user found" }, "footer": "ThirdCC @ 2020" } diff --git a/src/main/webapp/i18n/zh-cn/clubFamily.json b/src/main/webapp/i18n/zh-cn/clubFamily.json index 611514ea..def0919e 100644 --- a/src/main/webapp/i18n/zh-cn/clubFamily.json +++ b/src/main/webapp/i18n/zh-cn/clubFamily.json @@ -10,17 +10,18 @@ "member": { "title": "CC家族成员", "createLabel": "添加新CC家族成员", + "editLabel": "更新CC家族成员", "createOrEditLabel": "添加或编辑CC家族成员", "notFound": "未发现任何CC家族成员" }, - "created": "Club Family {{ param }} 创建成功", - "updated": "Club Family {{ param }} 更新成功", - "deleted": "Club Family {{ param }} 删除成功", + "created": "CC家族 {{ param }} 创建成功", + "updated": "CC家族 {{ param }} 更新成功", + "deleted": "CC家族 {{ param }} 删除成功", "delete": { - "question": "你确定要删除 Club Family {{ id }} 吗?" + "question": "你确定要删除 CC家族 {{ id }} 吗?" }, "detail": { - "title": "Club Family" + "title": "CC家族" }, "name": "名称", "slogan": "口号", @@ -39,7 +40,7 @@ }, "kongque": { "name": "孔雀鱼", - "slogan": "我们是比精英中的精英还要更精英的精英", + "slogan": "我们是比精英中的精英还要精英的精英", "description": "孔雀家的鱼儿都是棒棒哒" }, "qicai": { @@ -51,7 +52,8 @@ "name": "小丑鱼", "slogan": "Nemo Nemo, 不再Emo", "description": "小丑家的鱼儿总是充满正能量,让你远离负能量" - } + }, + "none": "无" } } } diff --git a/src/main/webapp/i18n/zh-cn/global.json b/src/main/webapp/i18n/zh-cn/global.json index 1842101a..6f807e27 100644 --- a/src/main/webapp/i18n/zh-cn/global.json +++ b/src/main/webapp/i18n/zh-cn/global.json @@ -165,7 +165,9 @@ "emailexists": "该邮箱已被使用!", "idexists": "新建的 {{entityName}} 不能包含ID", "noname": "新建的 {{entityName}} 不能没有名字", - "idnull": "Invalid ID" + "idnull": "Id 无效", + "noResultFound": "未发现任何结果", + "noUserFound": "未发现任何用户" }, "footer": "马大叁舍 ~ 鱼之家 @ 2020" } diff --git a/src/main/webapp/i18n/zh-cn/userCCInfo.json b/src/main/webapp/i18n/zh-cn/userCCInfo.json index cc28ed38..35d44661 100644 --- a/src/main/webapp/i18n/zh-cn/userCCInfo.json +++ b/src/main/webapp/i18n/zh-cn/userCCInfo.json @@ -2,25 +2,25 @@ "clubmanagementApp": { "userCCInfo": { "home": { - "title": "User CC Infos", - "createLabel": "创建新 User CC Info", - "createOrEditLabel": "创建或编辑 User CC Info", - "notFound": "No User CC Info found" + "title": "个人宿舍资料", + "createLabel": "创建新 个人宿舍资料", + "createOrEditLabel": "创建或编辑 个人宿舍资料", + "notFound": "无个人宿舍资料" }, - "created": "User CC Info {{ param }} 创建成功", - "updated": "User CC Info {{ param }} 更新成功", - "deleted": "User CC Info {{ param }} 删除成功", + "created": "个人宿舍资料 {{ param }} 创建成功", + "updated": "个人宿舍资料 {{ param }} 更新成功", + "deleted": "个人宿舍资料 {{ param }} 删除成功", "delete": { - "question": "你确定要删除 User CC Info {{ id }} 吗?" + "question": "你确定要删除 个人宿舍资料 {{ id }} 吗?" }, "detail": { - "title": "User CC Info" + "title": "个人宿舍资料" }, - "userId": "User Id", - "clubFamilyId": "Club Family Id", - "familyRole": "Family Role", - "yearSession": "Year Session", - "clubFamilyName": "Club Family Name" + "userId": "用户 Id", + "clubFamilyId": "家族 Id", + "familyRole": "家中角色", + "yearSession": "学年", + "clubFamilyName": "家族名称" } } } diff --git a/src/main/webapp/swagger-ui/index.html b/src/main/webapp/swagger-ui/index.html index 2345ea20..f7279343 100644 --- a/src/main/webapp/swagger-ui/index.html +++ b/src/main/webapp/swagger-ui/index.html @@ -1,28 +1,28 @@ - - + + Swagger UI - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -30,137 +30,128 @@ - + function maybePrefix(location, withRelativePath) { + var pat = /^https?:\/\//i; + if (pat.test(location)) { + return location; + } + return withRelativePath + location; + } + + function initializeBaseUrl() { + var relativeLocation = springfox.baseUrl(); + + $('#input_baseUrl').hide(); + + $.getJSON(relativeLocation + '/swagger-resources', function (data) { + var $urlDropdown = $('#select_baseUrl'); + $urlDropdown.empty(); + $.each(data, function (i, resource) { + var option = $('') + .attr('value', maybePrefix(resource.location, relativeLocation)) + .text(resource.name + ' (' + resource.location + ')'); + $urlDropdown.append(option); + }); + $urlDropdown.change(); + }); + } + }); + + - -