Set app visibility

This commit is contained in:
Paweł Malak 2021-11-08 23:40:30 +01:00
parent ee9aefa4fa
commit d1738a0a3e
7 changed files with 127 additions and 105 deletions

View file

@ -8,6 +8,7 @@ import classes from './AppForm.module.css';
import ModalForm from '../../UI/Forms/ModalForm/ModalForm';
import InputGroup from '../../UI/Forms/InputGroup/InputGroup';
import Button from '../../UI/Buttons/Button/Button';
import { inputHandler, newAppTemplate } from '../../../utility';
interface ComponentProps {
modalHandler: () => void;
@ -19,32 +20,27 @@ interface ComponentProps {
const AppForm = (props: ComponentProps): JSX.Element => {
const [useCustomIcon, toggleUseCustomIcon] = useState<boolean>(false);
const [customIcon, setCustomIcon] = useState<File | null>(null);
const [formData, setFormData] = useState<NewApp>({
name: '',
url: '',
icon: '',
});
const [formData, setFormData] = useState<NewApp>(newAppTemplate);
useEffect(() => {
if (props.app) {
setFormData({
name: props.app.name,
url: props.app.url,
icon: props.app.icon,
...props.app,
});
} else {
setFormData({
name: '',
url: '',
icon: '',
});
setFormData(newAppTemplate);
}
}, [props.app]);
const inputChangeHandler = (e: ChangeEvent<HTMLInputElement>): void => {
setFormData({
...formData,
[e.target.name]: e.target.value,
const inputChangeHandler = (
e: ChangeEvent<HTMLInputElement | HTMLSelectElement>,
options?: { isNumber?: boolean; isBool?: boolean }
) => {
inputHandler<NewApp>({
e,
options,
setStateHandler: setFormData,
state: formData,
});
};
@ -86,11 +82,7 @@ const AppForm = (props: ComponentProps): JSX.Element => {
}
}
setFormData({
name: '',
url: '',
icon: '',
});
setFormData(newAppTemplate);
};
return (
@ -98,6 +90,7 @@ const AppForm = (props: ComponentProps): JSX.Element => {
modalHandler={props.modalHandler}
formHandler={formSubmitHandler}
>
{/* NAME */}
<InputGroup>
<label htmlFor="name">App Name</label>
<input
@ -110,6 +103,8 @@ const AppForm = (props: ComponentProps): JSX.Element => {
onChange={(e) => inputChangeHandler(e)}
/>
</InputGroup>
{/* URL */}
<InputGroup>
<label htmlFor="url">App URL</label>
<input
@ -121,17 +116,9 @@ const AppForm = (props: ComponentProps): JSX.Element => {
value={formData.url}
onChange={(e) => inputChangeHandler(e)}
/>
<span>
<a
href="https://github.com/pawelmalak/flame#supported-url-formats-for-applications-and-bookmarks"
target="_blank"
rel="noreferrer"
>
{' '}
Check supported URL formats
</a>
</span>
</InputGroup>
{/* ICON */}
{!useCustomIcon ? (
// use mdi icon
<InputGroup>
@ -182,6 +169,21 @@ const AppForm = (props: ComponentProps): JSX.Element => {
</span>
</InputGroup>
)}
{/* VISIBILITY */}
<InputGroup>
<label htmlFor="isPublic">App visibility</label>
<select
id="isPublic"
name="isPublic"
value={formData.isPublic ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>Visible (anyone can access it)</option>
<option value={0}>Hidden (authentication required)</option>
</select>
</InputGroup>
{!props.app ? (
<Button>Add new application</Button>
) : (

View file

@ -114,7 +114,7 @@ const AppTable = (props: ComponentProps): JSX.Element => {
<Droppable droppableId="apps">
{(provided) => (
<Table
headers={['Name', 'URL', 'Icon', 'Actions']}
headers={['Name', 'URL', 'Icon', 'Visibility', 'Actions']}
innerRef={provided.innerRef}
>
{localApps.map((app: App, index): JSX.Element => {
@ -143,6 +143,9 @@ const AppTable = (props: ComponentProps): JSX.Element => {
<td style={{ width: '200px' }}>{app.name}</td>
<td style={{ width: '200px' }}>{app.url}</td>
<td style={{ width: '200px' }}>{app.icon}</td>
<td style={{ width: '200px' }}>
{app.isPublic ? 'Visible' : 'Hidden'}
</td>
{!snapshot.isDragging && (
<td className={classes.TableActions}>
<div

View file

@ -23,6 +23,9 @@ import AppGrid from './AppGrid/AppGrid';
import AppForm from './AppForm/AppForm';
import AppTable from './AppTable/AppTable';
// Utils
import { appTemplate } from '../../utility';
interface ComponentProps {
getApps: Function;
apps: App[];
@ -36,16 +39,7 @@ const Apps = (props: ComponentProps): JSX.Element => {
const [modalIsOpen, setModalIsOpen] = useState(false);
const [isInEdit, setIsInEdit] = useState(false);
const [isInUpdate, setIsInUpdate] = useState(false);
const [appInUpdate, setAppInUpdate] = useState<App>({
name: 'string',
url: 'string',
icon: 'string',
isPinned: false,
orderId: 0,
id: 0,
createdAt: new Date(),
updatedAt: new Date(),
});
const [appInUpdate, setAppInUpdate] = useState<App>(appTemplate);
useEffect(() => {
if (apps.length === 0) {

View file

@ -1,15 +1,13 @@
import { Model } from '.';
export interface App extends Model {
name: string;
url: string;
icon: string;
isPinned: boolean;
orderId: number;
}
export interface NewApp {
name: string;
url: string;
icon: string;
}
isPublic: boolean;
}
export interface App extends Model, NewApp {
orderId: number;
isPinned: boolean;
}

View file

@ -11,108 +11,115 @@ export interface State {
const initialState: State = {
loading: true,
apps: [],
errors: undefined
}
errors: undefined,
};
const getApps = (state: State, action: Action): State => {
return {
...state,
loading: true,
errors: undefined
}
}
errors: undefined,
};
};
const getAppsSuccess = (state: State, action: Action): State => {
return {
...state,
loading: false,
apps: action.payload
}
}
apps: action.payload,
};
};
const getAppsError = (state: State, action: Action): State => {
return {
...state,
loading: false,
errors: action.payload
}
}
errors: action.payload,
};
};
const pinApp = (state: State, action: Action): State => {
const tmpApps = [...state.apps];
const changedApp = tmpApps.find((app: App) => app.id === action.payload.id);
if (changedApp) {
changedApp.isPinned = action.payload.isPinned;
}
return {
...state,
apps: tmpApps
}
}
apps: tmpApps,
};
};
const addAppSuccess = (state: State, action: Action): State => {
return {
...state,
apps: [...state.apps, action.payload]
}
}
apps: [...state.apps, action.payload],
};
};
const deleteApp = (state: State, action: Action): State => {
const tmpApps = [...state.apps].filter((app: App) => app.id !== action.payload);
return {
...state,
apps: tmpApps
}
}
apps: [...state.apps].filter((app: App) => app.id !== action.payload),
};
};
const updateApp = (state: State, action: Action): State => {
const tmpApps = [...state.apps];
const appInUpdate = tmpApps.find((app: App) => app.id === action.payload.id);
if (appInUpdate) {
appInUpdate.name = action.payload.name;
appInUpdate.url = action.payload.url;
appInUpdate.icon = action.payload.icon;
}
const appIdx = state.apps.findIndex((app) => app.id === action.payload.id);
return {
...state,
apps: tmpApps
}
}
apps: [
...state.apps.slice(0, appIdx),
{
...action.payload,
},
...state.apps.slice(appIdx + 1),
],
};
};
const reorderApps = (state: State, action: Action): State => {
return {
...state,
apps: action.payload
}
}
apps: action.payload,
};
};
const sortApps = (state: State, action: Action): State => {
const sortedApps = sortData<App>(state.apps, action.payload);
return {
...state,
apps: sortedApps
}
}
apps: sortedApps,
};
};
const appReducer = (state = initialState, action: Action) => {
switch (action.type) {
case ActionTypes.getApps: return getApps(state, action);
case ActionTypes.getAppsSuccess: return getAppsSuccess(state, action);
case ActionTypes.getAppsError: return getAppsError(state, action);
case ActionTypes.pinApp: return pinApp(state, action);
case ActionTypes.addAppSuccess: return addAppSuccess(state, action);
case ActionTypes.deleteApp: return deleteApp(state, action);
case ActionTypes.updateApp: return updateApp(state, action);
case ActionTypes.reorderApps: return reorderApps(state, action);
case ActionTypes.sortApps: return sortApps(state, action);
default: return state;
case ActionTypes.getApps:
return getApps(state, action);
case ActionTypes.getAppsSuccess:
return getAppsSuccess(state, action);
case ActionTypes.getAppsError:
return getAppsError(state, action);
case ActionTypes.pinApp:
return pinApp(state, action);
case ActionTypes.addAppSuccess:
return addAppSuccess(state, action);
case ActionTypes.deleteApp:
return deleteApp(state, action);
case ActionTypes.updateApp:
return updateApp(state, action);
case ActionTypes.reorderApps:
return reorderApps(state, action);
case ActionTypes.sortApps:
return sortApps(state, action);
default:
return state;
}
}
};
export default appReducer;
export default appReducer;

View file

@ -0,0 +1,17 @@
import { App, NewApp } from '../../interfaces';
export const newAppTemplate: NewApp = {
name: '',
url: '',
icon: '',
isPublic: true,
};
export const appTemplate: App = {
...newAppTemplate,
isPinned: false,
orderId: 0,
id: 0,
createdAt: new Date(),
updatedAt: new Date(),
};

View file

@ -1,2 +1,3 @@
export * from './configTemplate';
export * from './settingsTemplate';
export * from './appTemplate';