mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	refactor: port global settings to TS/hooks (#679)
* refactor: add ref support to PermissionSwitch * refactor: port global settings to TS/hooks * refactor: fix file extension * refactor: format file * refactor: fix inconsistent locationSettings prop * refactor: use correct locationSettings hook * refactor: use objects for settings hooks
This commit is contained in:
		
							parent
							
								
									36f59b2290
								
							
						
					
					
						commit
						fee1894c34
					
				@ -31,6 +31,7 @@ import Dialogue from '../../../common/Dialogue';
 | 
			
		||||
import { CREATE_API_TOKEN_BUTTON } from '../../../../testIds';
 | 
			
		||||
import { Alert } from '@material-ui/lab';
 | 
			
		||||
import copy from 'copy-to-clipboard';
 | 
			
		||||
import { useLocationSettings } from "../../../../hooks/useLocationSettings";
 | 
			
		||||
 | 
			
		||||
interface IApiToken {
 | 
			
		||||
    createdAt: Date;
 | 
			
		||||
@ -41,16 +42,13 @@ interface IApiToken {
 | 
			
		||||
    environment: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IApiTokenList {
 | 
			
		||||
    location: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ApiTokenList = ({ location }: IApiTokenList) => {
 | 
			
		||||
const ApiTokenList = () => {
 | 
			
		||||
    const styles = useStyles();
 | 
			
		||||
    const { hasAccess } = useContext(AccessContext);
 | 
			
		||||
    const { uiConfig } = useUiConfig();
 | 
			
		||||
    const [showDelete, setShowDelete] = useState(false);
 | 
			
		||||
    const [delToken, setDeleteToken] = useState<IApiToken>();
 | 
			
		||||
    const { locationSettings } = useLocationSettings()
 | 
			
		||||
    const { setToastData } = useToast();
 | 
			
		||||
    const { tokens, loading, refetch, error } = useApiTokens();
 | 
			
		||||
    const { deleteToken } = useApiTokensApi();
 | 
			
		||||
@ -150,7 +148,7 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
 | 
			
		||||
                                >
 | 
			
		||||
                                    {formatDateWithLocale(
 | 
			
		||||
                                        item.createdAt,
 | 
			
		||||
                                        location.locale
 | 
			
		||||
                                        locationSettings.locale
 | 
			
		||||
                                    )}
 | 
			
		||||
                                </TableCell>
 | 
			
		||||
                                <TableCell
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ import AdminMenu from '../menu/AdminMenu';
 | 
			
		||||
import usePermissions from '../../../hooks/usePermissions';
 | 
			
		||||
import ConditionallyRender from '../../common/ConditionallyRender';
 | 
			
		||||
 | 
			
		||||
const ApiPage = ({ history, location }) => {
 | 
			
		||||
const ApiPage = ({ history }) => {
 | 
			
		||||
    const { isAdmin } = usePermissions();
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
@ -14,7 +14,7 @@ const ApiPage = ({ history, location }) => {
 | 
			
		||||
                condition={isAdmin()}
 | 
			
		||||
                show={<AdminMenu history={history} />}
 | 
			
		||||
            />
 | 
			
		||||
            <ApiTokenList location={location} />
 | 
			
		||||
            <ApiTokenList />
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
@ -22,7 +22,6 @@ const ApiPage = ({ history, location }) => {
 | 
			
		||||
ApiPage.propTypes = {
 | 
			
		||||
    match: PropTypes.object.isRequired,
 | 
			
		||||
    history: PropTypes.object.isRequired,
 | 
			
		||||
    location: PropTypes.object.isRequired,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default ApiPage;
 | 
			
		||||
 | 
			
		||||
@ -14,15 +14,15 @@ import HeaderTitle from '../../common/HeaderTitle';
 | 
			
		||||
import ConditionallyRender from '../../common/ConditionallyRender';
 | 
			
		||||
import { formatApiPath } from '../../../utils/format-path';
 | 
			
		||||
import useInvoices from '../../../hooks/api/getters/useInvoices/useInvoices';
 | 
			
		||||
import { useLocation } from 'react-router-dom';
 | 
			
		||||
import { IInvoice } from '../../../interfaces/invoice';
 | 
			
		||||
import { useLocationSettings } from '../../../hooks/useLocationSettings';
 | 
			
		||||
 | 
			
		||||
const PORTAL_URL = formatApiPath('api/admin/invoices/portal');
 | 
			
		||||
 | 
			
		||||
const InvoiceList = () => {
 | 
			
		||||
    const { refetchInvoices, invoices } = useInvoices();
 | 
			
		||||
    const [isLoaded, setLoaded] = useState(false);
 | 
			
		||||
    const location = useLocation();
 | 
			
		||||
    const { locationSettings } = useLocationSettings();
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        refetchInvoices();
 | 
			
		||||
@ -89,7 +89,7 @@ const InvoiceList = () => {
 | 
			
		||||
                                            {item.dueDate &&
 | 
			
		||||
                                                formatDateWithLocale(
 | 
			
		||||
                                                    item.dueDate,
 | 
			
		||||
                                                    location.locale
 | 
			
		||||
                                                    locationSettings.locale
 | 
			
		||||
                                                )}
 | 
			
		||||
                                        </TableCell>
 | 
			
		||||
                                        <TableCell
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ import AccessContext from '../../../../../contexts/AccessContext';
 | 
			
		||||
import { IUser } from '../../../../../interfaces/user';
 | 
			
		||||
import { useStyles } from './UserListItem.styles';
 | 
			
		||||
import { useHistory } from 'react-router-dom';
 | 
			
		||||
import { ILocationSettings } from "../../../../../hooks/useLocationSettings";
 | 
			
		||||
 | 
			
		||||
interface IUserListItemProps {
 | 
			
		||||
    user: IUser;
 | 
			
		||||
@ -21,11 +22,7 @@ interface IUserListItemProps {
 | 
			
		||||
    openUpdateDialog: (user: IUser) => (e: SyntheticEvent) => void;
 | 
			
		||||
    openPwDialog: (user: IUser) => (e: SyntheticEvent) => void;
 | 
			
		||||
    openDelDialog: (user: IUser) => (e: SyntheticEvent) => void;
 | 
			
		||||
    location: ILocation;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface ILocation {
 | 
			
		||||
    locale: string;
 | 
			
		||||
    locationSettings: ILocationSettings;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const UserListItem = ({
 | 
			
		||||
@ -34,7 +31,7 @@ const UserListItem = ({
 | 
			
		||||
    openDelDialog,
 | 
			
		||||
    openPwDialog,
 | 
			
		||||
    openUpdateDialog,
 | 
			
		||||
    location,
 | 
			
		||||
    locationSettings,
 | 
			
		||||
}: IUserListItemProps) => {
 | 
			
		||||
    const { hasAccess } = useContext(AccessContext);
 | 
			
		||||
    const history = useHistory()
 | 
			
		||||
@ -54,7 +51,7 @@ const UserListItem = ({
 | 
			
		||||
            </TableCell>
 | 
			
		||||
            <TableCell>
 | 
			
		||||
                <span data-loading>
 | 
			
		||||
                    {formatDateWithLocale(user.createdAt, location.locale)}
 | 
			
		||||
                    {formatDateWithLocale(user.createdAt, locationSettings.locale)}
 | 
			
		||||
                </span>
 | 
			
		||||
            </TableCell>
 | 
			
		||||
            <TableCell className={styles.leftTableCell}>
 | 
			
		||||
 | 
			
		||||
@ -20,10 +20,10 @@ import loadingData from './loadingData';
 | 
			
		||||
import useLoading from '../../../../hooks/useLoading';
 | 
			
		||||
import usePagination from '../../../../hooks/usePagination';
 | 
			
		||||
import PaginateUI from '../../../common/PaginateUI/PaginateUI';
 | 
			
		||||
import { useHistory } from 'react-router-dom';
 | 
			
		||||
import { IUser } from '../../../../interfaces/user';
 | 
			
		||||
import IRole from '../../../../interfaces/role';
 | 
			
		||||
import useToast from '../../../../hooks/useToast';
 | 
			
		||||
import { useLocationSettings } from "../../../../hooks/useLocationSettings";
 | 
			
		||||
 | 
			
		||||
const UsersList = () => {
 | 
			
		||||
    const { users, roles, refetch, loading } = useUsers();
 | 
			
		||||
@ -35,9 +35,8 @@ const UsersList = () => {
 | 
			
		||||
        userLoading,
 | 
			
		||||
        userApiErrors,
 | 
			
		||||
    } = useAdminUsersApi();
 | 
			
		||||
    const history = useHistory();
 | 
			
		||||
    const { location } = history;
 | 
			
		||||
    const { hasAccess } = useContext(AccessContext);
 | 
			
		||||
    const { locationSettings } = useLocationSettings()
 | 
			
		||||
    const [pwDialog, setPwDialog] = useState<{ open: boolean; user?: IUser }>({
 | 
			
		||||
        open: false,
 | 
			
		||||
    });
 | 
			
		||||
@ -104,7 +103,7 @@ const UsersList = () => {
 | 
			
		||||
                    user={user}
 | 
			
		||||
                    openPwDialog={openPwDialog}
 | 
			
		||||
                    openDelDialog={openDelDialog}
 | 
			
		||||
                    location={location}
 | 
			
		||||
                    locationSettings={locationSettings}
 | 
			
		||||
                    renderRole={renderRole}
 | 
			
		||||
                />
 | 
			
		||||
            ));
 | 
			
		||||
@ -117,7 +116,7 @@ const UsersList = () => {
 | 
			
		||||
                    user={user}
 | 
			
		||||
                    openPwDialog={openPwDialog}
 | 
			
		||||
                    openDelDialog={openDelDialog}
 | 
			
		||||
                    location={location}
 | 
			
		||||
                    locationSettings={locationSettings}
 | 
			
		||||
                    renderRole={renderRole}
 | 
			
		||||
                />
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ test('renders correctly if no application', () => {
 | 
			
		||||
                    storeApplicationMetaData={jest.fn()}
 | 
			
		||||
                    deleteApplication={jest.fn()}
 | 
			
		||||
                    history={{}}
 | 
			
		||||
                    locationSettings={{ locale: 'en-GB' }}
 | 
			
		||||
                />
 | 
			
		||||
            </AccessProvider>
 | 
			
		||||
        )
 | 
			
		||||
@ -77,7 +78,7 @@ test('renders correctly without permission', () => {
 | 
			
		||||
                                url: 'http://example.org',
 | 
			
		||||
                                description: 'app description',
 | 
			
		||||
                            }}
 | 
			
		||||
                            location={{ locale: 'en-GB' }}
 | 
			
		||||
                            locationSettings={{ locale: 'en-GB' }}
 | 
			
		||||
                        />
 | 
			
		||||
                    </AccessProvider>
 | 
			
		||||
                </ThemeProvider>
 | 
			
		||||
@ -140,7 +141,7 @@ test('renders correctly with permissions', () => {
 | 
			
		||||
                                url: 'http://example.org',
 | 
			
		||||
                                description: 'app description',
 | 
			
		||||
                            }}
 | 
			
		||||
                            location={{ locale: 'en-GB' }}
 | 
			
		||||
                            locationSettings={{ locale: 'en-GB' }}
 | 
			
		||||
                        />
 | 
			
		||||
                    </AccessProvider>
 | 
			
		||||
                </ThemeProvider>
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ class ClientApplications extends PureComponent {
 | 
			
		||||
        fetchApplication: PropTypes.func.isRequired,
 | 
			
		||||
        appName: PropTypes.string,
 | 
			
		||||
        application: PropTypes.object,
 | 
			
		||||
        location: PropTypes.object,
 | 
			
		||||
        locationSettings: PropTypes.object.isRequired,
 | 
			
		||||
        storeApplicationMetaData: PropTypes.func.isRequired,
 | 
			
		||||
        deleteApplication: PropTypes.func.isRequired,
 | 
			
		||||
        history: PropTypes.object.isRequired,
 | 
			
		||||
@ -54,8 +54,8 @@ class ClientApplications extends PureComponent {
 | 
			
		||||
            .finally(() => this.setState({ loading: false }));
 | 
			
		||||
    }
 | 
			
		||||
    formatFullDateTime = v =>
 | 
			
		||||
        formatFullDateTimeWithLocale(v, this.props.location.locale);
 | 
			
		||||
    formatDate = v => formatDateWithLocale(v, this.props.location.locale);
 | 
			
		||||
        formatFullDateTimeWithLocale(v, this.props.locationSettings.locale);
 | 
			
		||||
    formatDate = v => formatDateWithLocale(v, this.props.locationSettings.locale);
 | 
			
		||||
 | 
			
		||||
    deleteApplication = async evt => {
 | 
			
		||||
        evt.preventDefault();
 | 
			
		||||
 | 
			
		||||
@ -1,23 +0,0 @@
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import ApplicationEdit from './application-edit-component';
 | 
			
		||||
import { fetchApplication, storeApplicationMetaData, deleteApplication } from './../../store/application/actions';
 | 
			
		||||
 | 
			
		||||
const mapStateToProps = (state, props) => {
 | 
			
		||||
    let application = state.applications.getIn(['apps', props.appName]);
 | 
			
		||||
    const location = state.settings.toJS().location || {};
 | 
			
		||||
    if (application) {
 | 
			
		||||
        application = application.toJS();
 | 
			
		||||
    }
 | 
			
		||||
    return {
 | 
			
		||||
        application,
 | 
			
		||||
        location,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Container = connect(mapStateToProps, {
 | 
			
		||||
    fetchApplication,
 | 
			
		||||
    storeApplicationMetaData,
 | 
			
		||||
    deleteApplication,
 | 
			
		||||
})(ApplicationEdit);
 | 
			
		||||
 | 
			
		||||
export default Container;
 | 
			
		||||
@ -0,0 +1,30 @@
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import ApplicationEdit from './application-edit-component';
 | 
			
		||||
import {
 | 
			
		||||
    deleteApplication,
 | 
			
		||||
    fetchApplication,
 | 
			
		||||
    storeApplicationMetaData,
 | 
			
		||||
} from '../../store/application/actions';
 | 
			
		||||
import { useLocationSettings } from '../../hooks/useLocationSettings';
 | 
			
		||||
 | 
			
		||||
const ApplicationEditContainer = props => {
 | 
			
		||||
    const { locationSettings } = useLocationSettings();
 | 
			
		||||
 | 
			
		||||
    return <ApplicationEdit {...props} locationSettings={locationSettings} />;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mapStateToProps = (state, props) => {
 | 
			
		||||
    let application = state.applications.getIn(['apps', props.appName]);
 | 
			
		||||
    if (application) {
 | 
			
		||||
        application = application.toJS();
 | 
			
		||||
    }
 | 
			
		||||
    return {
 | 
			
		||||
        application,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default connect(mapStateToProps, {
 | 
			
		||||
    fetchApplication,
 | 
			
		||||
    storeApplicationMetaData,
 | 
			
		||||
    deleteApplication,
 | 
			
		||||
})(ApplicationEditContainer);
 | 
			
		||||
@ -13,7 +13,11 @@ interface IPermissionSwitchProps extends OverridableComponent<any> {
 | 
			
		||||
    checked: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const PermissionSwitch: React.FC<IPermissionSwitchProps> = ({
 | 
			
		||||
const PermissionSwitch = React.forwardRef<
 | 
			
		||||
    HTMLButtonElement,
 | 
			
		||||
    IPermissionSwitchProps
 | 
			
		||||
>((props, ref) => {
 | 
			
		||||
    const {
 | 
			
		||||
        permission,
 | 
			
		||||
        tooltip = '',
 | 
			
		||||
        disabled,
 | 
			
		||||
@ -22,7 +26,8 @@ const PermissionSwitch: React.FC<IPermissionSwitchProps> = ({
 | 
			
		||||
        checked,
 | 
			
		||||
        onChange,
 | 
			
		||||
        ...rest
 | 
			
		||||
}) => {
 | 
			
		||||
    } = props;
 | 
			
		||||
 | 
			
		||||
    const { hasAccess } = useContext(AccessContext);
 | 
			
		||||
 | 
			
		||||
    let access;
 | 
			
		||||
@ -45,11 +50,12 @@ const PermissionSwitch: React.FC<IPermissionSwitchProps> = ({
 | 
			
		||||
                    onChange={onChange}
 | 
			
		||||
                    disabled={disabled || !access}
 | 
			
		||||
                    checked={checked}
 | 
			
		||||
                    ref={ref}
 | 
			
		||||
                    {...rest}
 | 
			
		||||
                />
 | 
			
		||||
            </span>
 | 
			
		||||
        </Tooltip>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default PermissionSwitch;
 | 
			
		||||
 | 
			
		||||
@ -1,25 +1,21 @@
 | 
			
		||||
import { Tooltip } from '@material-ui/core';
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import { formatDateWithLocale, formatFullDateTimeWithLocale } from '../../../common/util';
 | 
			
		||||
import { useLocationSettings } from "../../../../hooks/useLocationSettings";
 | 
			
		||||
 | 
			
		||||
interface CreatedAtProps {
 | 
			
		||||
    time: Date;
 | 
			
		||||
    //@ts-ignore
 | 
			
		||||
    location: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const CreatedAt = ({time, location}: CreatedAtProps) => {
 | 
			
		||||
const CreatedAt = ({time}: CreatedAtProps) => {
 | 
			
		||||
    const { locationSettings } = useLocationSettings();
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <Tooltip title={`Created at ${formatFullDateTimeWithLocale(time, location.locale)}`}>
 | 
			
		||||
        <Tooltip title={`Created at ${formatFullDateTimeWithLocale(time, locationSettings.locale)}`}>
 | 
			
		||||
            <span>
 | 
			
		||||
                {formatDateWithLocale(time, location.locale)}
 | 
			
		||||
                {formatDateWithLocale(time, locationSettings.locale)}
 | 
			
		||||
            </span>
 | 
			
		||||
        </Tooltip>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const mapStateToProps = (state: any) => ({
 | 
			
		||||
    location: state.settings.toJS().location,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default connect(mapStateToProps)(CreatedAt);
 | 
			
		||||
export default CreatedAt;
 | 
			
		||||
 | 
			
		||||
@ -11,24 +11,21 @@ import EventCard from './EventCard/EventCard';
 | 
			
		||||
import { useStyles } from './EventLog.styles.js';
 | 
			
		||||
 | 
			
		||||
const EventLog = ({
 | 
			
		||||
    updateSetting,
 | 
			
		||||
    title,
 | 
			
		||||
    history,
 | 
			
		||||
    settings,
 | 
			
		||||
    eventSettings,
 | 
			
		||||
    setEventSettings,
 | 
			
		||||
    locationSettings,
 | 
			
		||||
    displayInline,
 | 
			
		||||
    location,
 | 
			
		||||
    hideName,
 | 
			
		||||
}) => {
 | 
			
		||||
    const styles = useStyles();
 | 
			
		||||
    const toggleShowDiff = () => {
 | 
			
		||||
        updateSetting('showData', !settings.showData);
 | 
			
		||||
        setEventSettings({ showData: !eventSettings.showData });
 | 
			
		||||
    };
 | 
			
		||||
    const formatFulldateTime = v => {
 | 
			
		||||
        return formatFullDateTimeWithLocale(v, location.locale);
 | 
			
		||||
        return formatFullDateTimeWithLocale(v, locationSettings.locale);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const showData = settings.showData;
 | 
			
		||||
 | 
			
		||||
    if (!history || history.length < 0) {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
@ -44,7 +41,7 @@ const EventLog = ({
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (showData) {
 | 
			
		||||
    if (eventSettings.showData) {
 | 
			
		||||
        entries = history.map(entry => (
 | 
			
		||||
            <EventJson key={`log${entry.id}`} entry={entry} />
 | 
			
		||||
        ));
 | 
			
		||||
@ -63,7 +60,7 @@ const EventLog = ({
 | 
			
		||||
                        <FormControlLabel
 | 
			
		||||
                            control={
 | 
			
		||||
                                <Switch
 | 
			
		||||
                                    checked={showData}
 | 
			
		||||
                                    checked={eventSettings.showData}
 | 
			
		||||
                                    onChange={toggleShowDiff}
 | 
			
		||||
                                    color="primary"
 | 
			
		||||
                                />
 | 
			
		||||
@ -82,12 +79,12 @@ const EventLog = ({
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
EventLog.propTypes = {
 | 
			
		||||
    updateSettings: PropTypes.func,
 | 
			
		||||
    history: PropTypes.array,
 | 
			
		||||
    eventSettings: PropTypes.object.isRequired,
 | 
			
		||||
    setEventSettings: PropTypes.func.isRequired,
 | 
			
		||||
    locationSettings: PropTypes.object.isRequired,
 | 
			
		||||
    title: PropTypes.string,
 | 
			
		||||
    settings: PropTypes.object,
 | 
			
		||||
    displayInline: PropTypes.bool,
 | 
			
		||||
    location: PropTypes.object,
 | 
			
		||||
    hideName: PropTypes.bool,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default EventLog;
 | 
			
		||||
 | 
			
		||||
@ -1,18 +0,0 @@
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import EventLog from './EventLog';
 | 
			
		||||
import { updateSettingForGroup } from '../../../store/settings/actions';
 | 
			
		||||
 | 
			
		||||
const mapStateToProps = state => {
 | 
			
		||||
    const settings = state.settings.toJS().history || {};
 | 
			
		||||
    const location = state.settings.toJS().location || {};
 | 
			
		||||
    return {
 | 
			
		||||
        settings,
 | 
			
		||||
        location,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const EventLogContainer = connect(mapStateToProps, {
 | 
			
		||||
    updateSetting: updateSettingForGroup('history'),
 | 
			
		||||
})(EventLog);
 | 
			
		||||
 | 
			
		||||
export default EventLogContainer;
 | 
			
		||||
							
								
								
									
										27
									
								
								frontend/src/component/history/EventLog/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								frontend/src/component/history/EventLog/index.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
import EventLog from './EventLog';
 | 
			
		||||
import { useEventSettings } from "../../../hooks/useEventSettings";
 | 
			
		||||
import { useLocationSettings } from "../../../hooks/useLocationSettings";
 | 
			
		||||
 | 
			
		||||
interface IEventLogContainerProps {
 | 
			
		||||
    title: string;
 | 
			
		||||
    history: unknown[];
 | 
			
		||||
    displayInline?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const EventLogContainer = (props: IEventLogContainerProps) => {
 | 
			
		||||
    const { locationSettings } = useLocationSettings();
 | 
			
		||||
    const { eventSettings, setEventSettings } = useEventSettings();
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <EventLog
 | 
			
		||||
            title={props.title}
 | 
			
		||||
            history={props.history}
 | 
			
		||||
            eventSettings={eventSettings}
 | 
			
		||||
            setEventSettings={setEventSettings}
 | 
			
		||||
            locationSettings={locationSettings}
 | 
			
		||||
            displayInline={props.displayInline}
 | 
			
		||||
        />
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default EventLogContainer;
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { useEffect, useState } from 'react';
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
import classnames from 'classnames';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import OutsideClickHandler from 'react-outside-click-handler';
 | 
			
		||||
 | 
			
		||||
import { Avatar, Button } from '@material-ui/core';
 | 
			
		||||
@ -8,17 +7,19 @@ import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
 | 
			
		||||
import { useStyles } from './UserProfile.styles';
 | 
			
		||||
import { useCommonStyles } from '../../../common.styles';
 | 
			
		||||
import UserProfileContent from './UserProfileContent/UserProfileContent';
 | 
			
		||||
import { IUser } from '../../../interfaces/user';
 | 
			
		||||
import { IUser } from "../../../interfaces/user";
 | 
			
		||||
import { ILocationSettings } from "../../../hooks/useLocationSettings";
 | 
			
		||||
 | 
			
		||||
interface IUserProfileProps {
 | 
			
		||||
    profile: IUser;
 | 
			
		||||
    updateSettingLocation: (field: 'locale', value: string) => void;
 | 
			
		||||
    profile: IUser
 | 
			
		||||
    locationSettings: ILocationSettings
 | 
			
		||||
    setLocationSettings: React.Dispatch<React.SetStateAction<ILocationSettings>>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const UserProfile = ({
 | 
			
		||||
    profile,
 | 
			
		||||
    location,
 | 
			
		||||
    updateSettingLocation,
 | 
			
		||||
    locationSettings,
 | 
			
		||||
    setLocationSettings,
 | 
			
		||||
}: IUserProfileProps) => {
 | 
			
		||||
    const [showProfile, setShowProfile] = useState(false);
 | 
			
		||||
    const [currentLocale, setCurrentLocale] = useState<string>();
 | 
			
		||||
@ -40,17 +41,15 @@ const UserProfile = ({
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        const locale = location.locale || navigator.language;
 | 
			
		||||
        let found = possibleLocales.find(l =>
 | 
			
		||||
            l.toLowerCase().includes(locale.toLowerCase())
 | 
			
		||||
            l.toLowerCase().includes(locationSettings.locale.toLowerCase())
 | 
			
		||||
        );
 | 
			
		||||
        setCurrentLocale(found);
 | 
			
		||||
 | 
			
		||||
        if (!found) {
 | 
			
		||||
            setPossibleLocales(prev => [...prev, locale]);
 | 
			
		||||
            setPossibleLocales(prev => [...prev, locationSettings.locale]);
 | 
			
		||||
        }
 | 
			
		||||
        /* eslint-disable-next-line*/
 | 
			
		||||
    }, []);
 | 
			
		||||
    }, [locationSettings]);
 | 
			
		||||
 | 
			
		||||
    const email = profile ? profile.email : '';
 | 
			
		||||
    const imageUrl = email ? profile.imageUrl : 'unknown-user.png';
 | 
			
		||||
@ -75,7 +74,7 @@ const UserProfile = ({
 | 
			
		||||
                    showProfile={showProfile}
 | 
			
		||||
                    imageUrl={imageUrl}
 | 
			
		||||
                    profile={profile}
 | 
			
		||||
                    updateSettingLocation={updateSettingLocation}
 | 
			
		||||
                    setLocationSettings={setLocationSettings}
 | 
			
		||||
                    possibleLocales={possibleLocales}
 | 
			
		||||
                    setCurrentLocale={setCurrentLocale}
 | 
			
		||||
                    currentLocale={currentLocale}
 | 
			
		||||
@ -85,10 +84,4 @@ const UserProfile = ({
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
UserProfile.propTypes = {
 | 
			
		||||
    profile: PropTypes.object,
 | 
			
		||||
    location: PropTypes.object,
 | 
			
		||||
    updateSettingLocation: PropTypes.func.isRequired,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default UserProfile;
 | 
			
		||||
 | 
			
		||||
@ -18,25 +18,28 @@ import legacyStyles from '../../user.module.scss';
 | 
			
		||||
import { getBasePath } from '../../../../utils/format-path';
 | 
			
		||||
import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig';
 | 
			
		||||
import { IUser } from '../../../../interfaces/user';
 | 
			
		||||
import { ILocationSettings } from '../../../../hooks/useLocationSettings';
 | 
			
		||||
 | 
			
		||||
interface IUserProfileContentProps {
 | 
			
		||||
    showProfile: boolean;
 | 
			
		||||
    profile: IUser;
 | 
			
		||||
    possibleLocales: string[];
 | 
			
		||||
    updateSettingLocation: (field: 'locale', value: string) => void;
 | 
			
		||||
    imageUrl: string;
 | 
			
		||||
    currentLocale?: string;
 | 
			
		||||
    setCurrentLocale: (value: string) => void;
 | 
			
		||||
    setLocationSettings: React.Dispatch<
 | 
			
		||||
        React.SetStateAction<ILocationSettings>
 | 
			
		||||
    >;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const UserProfileContent = ({
 | 
			
		||||
    showProfile,
 | 
			
		||||
    profile,
 | 
			
		||||
    possibleLocales,
 | 
			
		||||
    updateSettingLocation,
 | 
			
		||||
    imageUrl,
 | 
			
		||||
    currentLocale,
 | 
			
		||||
    setCurrentLocale,
 | 
			
		||||
    setLocationSettings,
 | 
			
		||||
}: IUserProfileContentProps) => {
 | 
			
		||||
    const commonStyles = useCommonStyles();
 | 
			
		||||
    const { uiConfig } = useUiConfig();
 | 
			
		||||
@ -44,10 +47,6 @@ const UserProfileContent = ({
 | 
			
		||||
    const [editingProfile, setEditingProfile] = useState(false);
 | 
			
		||||
    const styles = useStyles();
 | 
			
		||||
 | 
			
		||||
    const setLocale = (value: string) => {
 | 
			
		||||
        updateSettingLocation('locale', value);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // @ts-expect-error
 | 
			
		||||
    const profileAvatarClasses = classnames(styles.avatar, {
 | 
			
		||||
        // @ts-expect-error
 | 
			
		||||
@ -61,9 +60,9 @@ const UserProfileContent = ({
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const handleChange = (e: React.ChangeEvent<{ value: unknown }>) => {
 | 
			
		||||
        const value = e.target.value as string;
 | 
			
		||||
        setCurrentLocale(value);
 | 
			
		||||
        setLocale(value);
 | 
			
		||||
        const locale = e.target.value as string;
 | 
			
		||||
        setCurrentLocale(locale);
 | 
			
		||||
        setLocationSettings({ locale });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
@ -99,19 +98,14 @@ const UserProfileContent = ({
 | 
			
		||||
                        condition={!editingProfile}
 | 
			
		||||
                        show={
 | 
			
		||||
                            <>
 | 
			
		||||
                                <ConditionallyRender
 | 
			
		||||
                                    condition={!uiConfig.disablePasswordAuth}
 | 
			
		||||
                                    show={
 | 
			
		||||
                                <ConditionallyRender condition={!uiConfig.disablePasswordAuth} show={
 | 
			
		||||
                                    <Button
 | 
			
		||||
                                        variant="contained"
 | 
			
		||||
                                            onClick={() =>
 | 
			
		||||
                                                setEditingProfile(true)
 | 
			
		||||
                                            }
 | 
			
		||||
                                        onClick={() => setEditingProfile(true)}
 | 
			
		||||
                                    >
 | 
			
		||||
                                        Update password
 | 
			
		||||
                                    </Button>
 | 
			
		||||
                                    }
 | 
			
		||||
                                />
 | 
			
		||||
                                } />
 | 
			
		||||
                                <div className={commonStyles.divider} />
 | 
			
		||||
                                <div className={legacyStyles.showUserSettings}>
 | 
			
		||||
                                    <FormControl
 | 
			
		||||
 | 
			
		||||
@ -1,27 +0,0 @@
 | 
			
		||||
import useUser from '../../../hooks/api/getters/useUser/useUser';
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
import UserProfile from './UserProfile';
 | 
			
		||||
import { updateSettingForGroup } from '../../../store/settings/actions';
 | 
			
		||||
 | 
			
		||||
const mapDispatchToProps = {
 | 
			
		||||
    updateSettingLocation: updateSettingForGroup('location'),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mapStateToProps = state => ({
 | 
			
		||||
    location: state.settings ? state.settings.toJS().location : {},
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default connect(
 | 
			
		||||
    mapStateToProps,
 | 
			
		||||
    mapDispatchToProps
 | 
			
		||||
)(props => {
 | 
			
		||||
    const user = useUser();
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <UserProfile
 | 
			
		||||
            location={props.location}
 | 
			
		||||
            updateSettingLocation={props.updateSettingLocation}
 | 
			
		||||
            profile={user.user}
 | 
			
		||||
        />
 | 
			
		||||
    );
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										18
									
								
								frontend/src/component/user/UserProfile/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								frontend/src/component/user/UserProfile/index.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
import useUser from '../../../hooks/api/getters/useUser/useUser';
 | 
			
		||||
import UserProfile from './UserProfile';
 | 
			
		||||
import { useLocationSettings } from '../../../hooks/useLocationSettings';
 | 
			
		||||
 | 
			
		||||
const UserProfileContainer = () => {
 | 
			
		||||
    const user = useUser();
 | 
			
		||||
    const { locationSettings, setLocationSettings } = useLocationSettings();
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <UserProfile
 | 
			
		||||
            locationSettings={locationSettings}
 | 
			
		||||
            setLocationSettings={setLocationSettings}
 | 
			
		||||
            profile={user.user}
 | 
			
		||||
        />
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default UserProfileContainer;
 | 
			
		||||
							
								
								
									
										27
									
								
								frontend/src/hooks/useEventSettings.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								frontend/src/hooks/useEventSettings.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
import { getBasePath } from '../utils/format-path';
 | 
			
		||||
import { createPersistentGlobalState } from './usePersistentGlobalState';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export interface IEventSettings {
 | 
			
		||||
    showData: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IUseEventSettingsOutput {
 | 
			
		||||
    eventSettings: IEventSettings;
 | 
			
		||||
    setEventSettings: React.Dispatch<React.SetStateAction<IEventSettings>>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const useEventSettings = (): IUseEventSettingsOutput => {
 | 
			
		||||
    const [eventSettings, setEventSettings] = useGlobalState();
 | 
			
		||||
 | 
			
		||||
    return { eventSettings, setEventSettings };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const createInitialValue = (): IEventSettings => {
 | 
			
		||||
    return { showData: false };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const useGlobalState = createPersistentGlobalState<IEventSettings>(
 | 
			
		||||
    `${getBasePath()}:useEventSettings:v1`,
 | 
			
		||||
    createInitialValue()
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										29
									
								
								frontend/src/hooks/useLocationSettings.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								frontend/src/hooks/useLocationSettings.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
import { getBasePath } from '../utils/format-path';
 | 
			
		||||
import { createPersistentGlobalState } from './usePersistentGlobalState';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export interface ILocationSettings {
 | 
			
		||||
    locale: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IUseLocationSettingsOutput {
 | 
			
		||||
    locationSettings: ILocationSettings;
 | 
			
		||||
    setLocationSettings: React.Dispatch<
 | 
			
		||||
        React.SetStateAction<ILocationSettings>
 | 
			
		||||
    >;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const useLocationSettings = (): IUseLocationSettingsOutput => {
 | 
			
		||||
    const [locationSettings, setLocationSettings] = useGlobalState();
 | 
			
		||||
 | 
			
		||||
    return { locationSettings, setLocationSettings };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const createInitialValue = (): ILocationSettings => {
 | 
			
		||||
    return { locale: navigator.language };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const useGlobalState = createPersistentGlobalState<ILocationSettings>(
 | 
			
		||||
    `${getBasePath()}:useLocationSettings:v1`,
 | 
			
		||||
    createInitialValue()
 | 
			
		||||
);
 | 
			
		||||
@ -7,7 +7,6 @@ import tagTypes from './tag-type';
 | 
			
		||||
import tags from './tag';
 | 
			
		||||
import strategies from './strategy';
 | 
			
		||||
import error from './error';
 | 
			
		||||
import settings from './settings';
 | 
			
		||||
import user from './user';
 | 
			
		||||
import applications from './application';
 | 
			
		||||
import uiConfig from './ui-config';
 | 
			
		||||
@ -27,7 +26,6 @@ const unleashStore = combineReducers({
 | 
			
		||||
    tags,
 | 
			
		||||
    featureTags,
 | 
			
		||||
    error,
 | 
			
		||||
    settings,
 | 
			
		||||
    user,
 | 
			
		||||
    applications,
 | 
			
		||||
    uiConfig,
 | 
			
		||||
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
export const UPDATE_SETTING = 'UPDATE_SETTING';
 | 
			
		||||
 | 
			
		||||
export const updateSetting = (group, field, value) => ({
 | 
			
		||||
    type: UPDATE_SETTING,
 | 
			
		||||
    group,
 | 
			
		||||
    field,
 | 
			
		||||
    value,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const updateSettingForGroup = group => (field, value) => updateSetting(group, field, value);
 | 
			
		||||
@ -1,44 +0,0 @@
 | 
			
		||||
import { fromJS } from 'immutable';
 | 
			
		||||
import { UPDATE_SETTING } from './actions';
 | 
			
		||||
import { USER_LOGOUT, USER_LOGIN } from '../user/actions';
 | 
			
		||||
 | 
			
		||||
import { getBasePath } from '../../utils/format-path';
 | 
			
		||||
 | 
			
		||||
const localStorage = window.localStorage || {
 | 
			
		||||
    setItem: () => {},
 | 
			
		||||
    getItem: () => {},
 | 
			
		||||
};
 | 
			
		||||
const basePath =  getBasePath();
 | 
			
		||||
const SETTINGS = `${basePath}:settings`;
 | 
			
		||||
 | 
			
		||||
const DEFAULT = fromJS({ location: {} });
 | 
			
		||||
 | 
			
		||||
function getInitState() {
 | 
			
		||||
    try {
 | 
			
		||||
        const state = JSON.parse(localStorage.getItem(SETTINGS));
 | 
			
		||||
        return state ? DEFAULT.merge(state) : DEFAULT;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        return DEFAULT;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function updateSetting(state, action) {
 | 
			
		||||
    const newState = state.updateIn([action.group, action.field], () => action.value);
 | 
			
		||||
 | 
			
		||||
    localStorage.setItem(SETTINGS, JSON.stringify(newState.toJSON()));
 | 
			
		||||
    return newState;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const settingStore = (state = getInitState(), action) => {
 | 
			
		||||
    switch (action.type) {
 | 
			
		||||
        case UPDATE_SETTING:
 | 
			
		||||
            return updateSetting(state, action);
 | 
			
		||||
        case USER_LOGOUT:
 | 
			
		||||
        case USER_LOGIN:
 | 
			
		||||
            return getInitState();
 | 
			
		||||
        default:
 | 
			
		||||
            return state;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default settingStore;
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user