| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982 |
- import React, { useState } from 'react';
- import { Container, Badge, FormGroup, Label, Input, Button, Collapse, Table, ListGroup, ListGroupItem } from 'reactstrap';
- import Paper, { Path, PaperScope, Point, Raster, Color } from 'paper';
- import { without, append, isNil, identity, includes, is } from 'ramda';
- import Axios from 'axios';
- import VALUES, { AgeVal, GenderVal, NonNativeVal, Filters, FilterVal, FilterStatus, EducationVal } from './services';
- import FileDownload from 'js-file-download';
- import map from './merseyside-nobg-white.png';
- import './Admin.css';
- const BACKEND = process.env.REACT_APP_BACKEND || '/backend';
- type PersonalInformation = {
- age: AgeVal,
- gender: GenderVal,
- genderCustom: string,
- birthPlace: string,
- currentPlace: string,
- levelEducation: EducationVal[],
- nonNative: NonNativeVal,
- }
- type Result = {
- personalInformation: PersonalInformation,
- canvas: OriginalCanvasData[],
- canvasSize: {
- width: number,
- height: number
- },
- email: string,
- id: number,
- }
- interface StateData {
- id: number,
- personalInformation: PersonalInformation,
- canvas: CanvasData[],
- // group: paper.Group,
- email: string
- };
- interface FormPath {
- name: string,
- soundExample: string,
- associations: string[],
- correctness: number,
- friendliness: number,
- pleasantness: number,
- trustworthiness: number
- }
- interface ShapeData extends FormPath, PersonalInformation {
- shapeId: number,
- id: number,
- }
- type OriginalCanvasData = {
- form: FormPath,
- path: string,
- }
- type CanvasData = {
- form: FormPath,
- path: paper.Path,
- label: paper.PointText
- };
- type AdminState = {
- original: StateData[],
- data: StateData[],
- canvas?: paper.PaperScope,
- height: number,
- focusedResponse?: StateData,
- path?: paper.Path,
- selectedArea?: paper.Item[],
- focusedDrawResponse?: {
- shape: paper.Item,
- label: paper.TextItem
- },
- };
- const mkPathLabel = (pathName: string, path: paper.Path) => {
- return new Paper.PointText({
- fillColor: '#4b505a',
- justification: 'center',
- fontWeight: 'bold',
- fontSize: '16px',
- point: path.bounds.center,
- content: pathName,
- visible: true
- })
- }
- const COLORS = [
- '#ffc6bc',
- '#fedea2',
- '#fff9b8',
- '#d3dbb2',
- '#a7d3d2',
- '#efe3f3',
- '#c4d0f5',
- '#c0ba98',
- ];
- const mkBgColor = (color: string) => {
- const _color = new Paper.Color(color);
- _color.alpha = 0.2;
- return _color;
- };
- const mkPath = (pathData: string, i: number, scale: number, data: ShapeData): paper.Path => {
- const color = COLORS[i % COLORS.length];
- const _path = new Path();
- _path.importJSON(pathData);
- _path.strokeColor = new Color(color);
- _path.strokeWidth = 2;
- _path.fillColor = mkBgColor(color)
- _path.selected = false;
- _path.scale(scale, new Point(0, 0));
- _path.data = data;
- return _path;
- }
- class Admin extends React.Component<{}, AdminState> {
- constructor(props: any) {
- super(props);
- this.state = {
- height: 100,
- canvas: undefined,
- original: [],
- data: [],
- focusedResponse: undefined,
- path: undefined,
- selectedArea: undefined,
- focusedDrawResponse: undefined,
- };
- }
- createPath = (canvas: paper.PaperScope) => (event: any) => {
- if(this.state.path === undefined) {
- this.toggleDrawings(this.state.data, false);
- let path = new canvas.Path({
- strokeColor: new Color('red'),
- strokeWidth: 5,
- });
- path.bringToFront();
- path.add(event.point);
- this.setState({ path });
- }
- }
- addPoint = (event: any) => {
- if (this.state.path && this.state.selectedArea === undefined) {
- this.state.path?.add(event.point)
- }
- };
- getItems = (canvas: paper.PaperScope) => () => {
- const { path, selectedArea } = this.state;
- if (path && !selectedArea) {
- path.add(path.firstSegment);
- path.closePath();
- path.simplify();
- const items = canvas.project.activeLayer.getItems({
- match: (value: paper.Item) => {
- return value.data.id && path.intersects(value);
- },
- class: Path,
- });
- items.forEach(item => {
- item.visible = true;
- });
- this.setState({
- selectedArea: items || []
- })
- }
- }
- toggleDrawings = (data: StateData[], visibility: boolean) => {
- data.forEach(result => {
- result.canvas.forEach(({ path, label }) => {
- path.visible = visibility;
- label.visible = visibility;
- })
- })
- }
- mkDrawingTool = (canvas: paper.PaperScope) => {
- let Tool = new canvas.Tool();
- Tool.onMouseDown = this.createPath(canvas);
- Tool.onMouseDrag = this.addPoint;
- Tool.onMouseUp = this.getItems(canvas);
- }
- componentDidMount = () => {
- const canvas = new PaperScope();
- canvas.setup('vom-admin-canvas');
- const height = canvas.view.size.width * 1.25;
- canvas.view.viewSize.height = height;
- this.mkDrawingTool(canvas);
- Axios.get<Result[]>(BACKEND, {
- headers: {
- 'X-Token': 'secret-potato',
- }
- }).then(response => {
- const _data = response.data.map((result, index) => {
- const item = {
- ...result,
- canvas: result.canvas.map((item, i) => {
- const pathData: ShapeData = {
- id: result.id,
- shapeId: i,
- ...result.personalInformation,
- ...item.form
- };
- const _path = mkPath(item.path, index, canvas.view.size.width / result.canvasSize.width, pathData);
- const _text = mkPathLabel(`${item.form.name} (${i})`, _path);
- return {
- path: _path,
- label: _text,
- form: item.form
- }
- }),
- };
- return item;
- })
-
- const raster = new Raster(map);
- raster.onLoad = () => {
- raster.position = canvas.view.center;
- raster.size = canvas.view.viewSize;
- raster.bringToFront();
- }
- this.setState({
- canvas,
- height,
- original: _data,
- data: _data,
- })
- })
- }
- isNotEducational = (value: AgeVal | GenderVal | NonNativeVal | string | EducationVal[]): value is AgeVal | GenderVal | NonNativeVal | string => {
- return is(String, value);
- }
- applyFilters = (filters: Filters) => {
- const results = this.state.original.filter(
- result => {
- const matches = VALUES.FILTER_KEYS.map(filterKey => {
- const filterValues = filters[filterKey];
- const resultValue = result.personalInformation[filterKey];
- if (filterValues) {
- if (this.isNotEducational(resultValue)) {
- return !isNil(filterValues.find(v => {
- return v === resultValue
- }));
- } else {
- return filterValues.some(v => includes(v, resultValue))
- }
- } else {
- return true;
- }
- }).every(identity);
- if (matches) {
- result.canvas.forEach(({ path, label }) => {
- path.visible = true;
- label.visible = true;
- })
- return true
- } else {
- result.canvas.forEach(({path, label}) => {
- path.visible = false;
- label.visible = false;
- })
- return false;
- }
- }
- )
- this.setState({
- data: results,
- focusedResponse: undefined,
- })
- }
- focusPath = (id: number) => {
- this.state.data.forEach(result => {
- if (result.id === id) {
- result.canvas.forEach(({path, label}) => {
- path.visible = true;
- label.visible = true;
- })
- this.setState({
- focusedResponse: result
- })
- } else {
- result.canvas.forEach(({ path, label}) => {
- path.visible = false;
- label.visible = false;
- })
- }
- });
- }
- clearFocus = () => {
- this.state.data.forEach(result => {
- result.canvas.forEach(({path, label}) => {
- label.visible = true;
- path.visible = true;
- })
- })
- this.setState({
- focusedResponse: undefined
- })
- }
- clearDrawing = () => {
- this.state.data.forEach(result => {
- result.canvas.forEach(({path, label}) => {
- path.visible = true;
- label.visible = true;
- path.selected = false;
- })
- });
- this.state.path?.remove();
- this.setState({
- path: undefined,
- selectedArea: undefined,
- focusedDrawResponse: undefined
- })
- }
- hideDrawing = (item: paper.Item) => {
- const { selectedArea } = this.state;
- if (selectedArea) {
- const newSelection = selectedArea.filter(i => {
- if (item.id === i.id) {
- i.visible = false;
- return false;
- } else {
- return true;
- }
- });
- this.setState({
- selectedArea: newSelection
- })
- }
- }
- downloadData = () => {
- Axios.get(`${BACKEND}/csv`, {
- headers: {
- 'X-Token': 'secret-potato',
- }
- }).then(response => {
- FileDownload(response.data, 'voices-of-merseyside.csv')
- })
- }
- downloadResultsData = () => {
- const data = this.state.selectedArea?.map(item => {
- return {
- id: item.data.id,
- shapeId: item.data.shapeId
- }
- });
- Axios.post(`${BACKEND}/csv`, data).then(response => {
- FileDownload(response.data, 'vom-drawing-results.csv');
- }).catch(e => {
- alert('error downloading the data, please try again')
- })
- }
- focuseDrawResponse = (item: ShapeData) => {
- const focused = this.state.data.find(response => response.id === item.id);
- let newFocused;
- if (focused) {
- focused.canvas.forEach(draw => {
- if (draw.path.data.shapeId === item.shapeId) {
- draw.path.bringToFront();
- draw.label.visible = true;
- draw.label.bringToFront();
- draw.path.selected = true;
- draw.path.selectedColor = new Color('red');
- newFocused = {
- shape: draw.path,
- label: draw.label
- }
- }
- });
- if (this.state.focusedDrawResponse) {
- // eslint-disable-next-line react/no-direct-mutation-state
- this.state.focusedDrawResponse.shape.selected = false;
- // eslint-disable-next-line react/no-direct-mutation-state
- this.state.focusedDrawResponse.label.visible = false;
- this.state.focusedDrawResponse.shape.sendToBack();
- }
- this.setState({
- focusedDrawResponse: newFocused
- })
- }
- }
- render() {
- return (
- <div className="App Admin">
- <Container fluid>
- <h2>Administration panel</h2>
- <div className="vom-results-data">
- <p>total responses: <Badge color="info">{this.state.original.length}</Badge></p>
- <p>showing: <Badge color="info">{this.state.data.length}</Badge></p>
- <p><Badge color="success" href="#" onClick={() => this.downloadData() }>download</Badge></p>
- </div>
- <div>
- <FilterPanel
- applyFilters={this.applyFilters}
- ></FilterPanel>
- </div>
- <div className="vom-canvii">
- <canvas id="vom-admin-canvas"></canvas>
- <div id="vom-results">
- <h4>Results</h4>
- <div id="vom-results-table" style={{height: this.state.height}}>
- {
- this.state.selectedArea ? (
- <>
- <p>drawings in area:
- <Badge color="info">{this.state.selectedArea.length}</Badge> <Badge color="warning" href="#" onClick={() => this.clearDrawing() }>clear drawing</Badge> <Badge color="success" href="#" onClick={() => this.downloadResultsData() }>download results</Badge>
- </p>
- <DrawingsTable
- items={this.state.selectedArea}
- focusResponse={this.focuseDrawResponse}
- hideResponse={this.hideDrawing}
- />
- </>
- ) : (
- <ResultsTable
- data={this.state.data}
- focusPath={this.focusPath}
- clearFocus={this.clearFocus}
- />
- )
- }
- </div>
- </div>
- </div>
- <div className="vom-selected-data">
- {
- this.state.selectedArea ? (
- <>
- <div>
-
- </div>
- <SelectedAreaTable items={this.state.selectedArea}></SelectedAreaTable>
- </>
- ) : null
- }
- </div>
- {
- this.state.focusedResponse ? (
- <div id="vom-results-panel">
- <div id="vom-focused-result" className="mt-3">
- <h4>Showing:</h4>
- <ViewResponse response={this.state.focusedResponse}/>
- </div>
- </div>
- ) : null
- }
- </Container>
- </div>
- )
- }
- }
- type SelectedAreaTotals = {
- age: {
- [k: string]: number,
- '1': number,
- '2': number,
- '3': number,
- '4': number,
- '5': number,
- '6': number
- },
- gender: {
- [k: string]: number,
- 'female': number,
- 'male': number,
- 'other': number
- },
- levelEducation: {
- [k: string]: number,
- '1': number,
- '2': number,
- '3': number,
- '4': number
- }
- }
- const SelectedAreaTable: React.FunctionComponent<{items: paper.Item[]}> = ({ items }) => {
- const init = {
- age: {
- '1': 0,
- '2': 0,
- '3': 0,
- '4': 0,
- '5': 0,
- '6': 0
- },
- gender: {
- 'female': 0,
- 'male': 0,
- 'other': 0
- },
- levelEducation: {
- '1': 0,
- '2': 0,
- '3': 0,
- '4': 0
- }
- };
- const [totals] = useState<SelectedAreaTotals>(items.reduce((totals, item) => {
- const data = item.data as ShapeData;
- const lvlEd = data.levelEducation ? data.levelEducation.reduce((tot, lvl) => {
- return {
- ...tot,
- [lvl]: totals.levelEducation[lvl] + 1
- }
- }, {}) : {};
- return data.age ? {
- age: {
- ...totals.age,
- [data.age]: totals.age[data.age] + 1
- },
- gender: {
- ...totals.gender,
- [data.gender]: totals.gender[data.gender] + 1
- },
- levelEducation: {
- ...totals.levelEducation,
- ...lvlEd
- }
- } : totals;
- }, { ...init }) || init)
- return (
- <>
- <h6>Age</h6>
- <Table bordered>
- <thead>
- <tr>
- <th>16-17</th>
- <th>18-25</th>
- <th>26-45</th>
- <th>46-65</th>
- <th>66-75</th>
- <th>75+</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- { Object.keys(totals.age).map((age, key) => (
- <td key={key}>{totals.age[age]}</td>
- ))}
- </tr>
- </tbody>
- </Table>
- <h6>Gender</h6>
- <Table bordered>
- <thead>
- <tr>
- <th>female</th>
- <th>male</th>
- <th>other</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- {
- Object.keys(totals.gender).map((gender, key) => (
- <td key={key}>{totals.gender[gender]}</td>
- ))
- }
- </tr>
- </tbody>
- </Table>
- <h6>Level of Education</h6>
- <Table bordered>
- <thead>
- <tr>
- <th>high school or lower</th>
- <th>bachelors</th>
- <th>masters</th>
- <th>doctorate</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- {
- Object.keys(totals.levelEducation).map((levelEducation, key) => (
- <td key={key}>{totals.levelEducation[levelEducation]}</td>
- ))
- }
- </tr>
- </tbody>
- </Table>
- </>
- )
- }
- type TableProps = {
- data: StateData[],
- focusPath: (id: number) => void,
- clearFocus: () => void,
- };
- const DrawingsTable: React.FunctionComponent<{
- items: paper.Item[],
- focusResponse: (i: ShapeData) => void,
- hideResponse: (i: paper.Item) => void
- }> = ({ items, focusResponse, hideResponse }) => {
- const [focused, setFocused] = useState<{id?: number, shapeId?: number}>({id: undefined, shapeId: undefined});
- return (
- <Table bordered >
- <thead>
- <tr>
- <th></th>
- <th>#</th>
- <th>age</th>
- <th>G</th>
- <th>education</th>
- <th>birth place</th>
- <th>current place</th>
- <th>NN</th>
- <th>name</th>
- <th>example</th>
- <th>associations</th>
- <th>C</th>
- <th>F</th>
- <th>P</th>
- <th>T</th>
- </tr>
- </thead>
- <tbody>
- {
- items.map((item, key) => {
- const d = item.data as ShapeData;
- return d.gender ? (
- <tr
- key={key}
- onClick={() => {
- focusResponse(d);
- setFocused({
- id: d.id,
- shapeId: d.shapeId
- })
- }}
- className={(focused.id === d.id && focused.shapeId === d.shapeId) ? 'data-focused' : ''}
- >
- <td><Badge href="#" onClick={() => { hideResponse(item) }}>X</Badge></td>
- <td>{d.id}</td>
- <td>{VALUES.AGE[d.age] || ''}</td>
- <td>{d.gender[0] || ''}</td>
- <td>{d.levelEducation.map(e => VALUES.EDUCATION[e] || '').join(', ')}</td>
- <td>{d.birthPlace}</td>
- <td>{d.currentPlace}</td>
- <td>{VALUES.NON_NATIVE[d.nonNative] || '-'}</td>
- <td>{d.name}</td>
- <td>{d.soundExample || '-'}</td>
- <td>{d.associations.join(', ')}</td>
- <td>{d.correctness}</td>
- <td>{d.friendliness}</td>
- <td>{d.pleasantness}</td>
- <td>{d.trustworthiness}</td>
- </tr>
- ) : null
- })
- }
- </tbody>
- </Table>
- )
- }
- const ResultsTable: React.FunctionComponent<TableProps> = ({ data, focusPath, clearFocus }) => {
- const [ focused, setFocused ] = useState<number>();
- return (
- <>
- <div className="vom-results-table__actions">
- <Button onClick={() => {
- setFocused(undefined);
- clearFocus();
- }} outline>clear focus</Button>
- </div>
- <Table bordered className="vom-table-results">
- <thead>
- <tr>
- <th>#</th>
- <th>age</th>
- <th>G</th>
- <th>education</th>
- <th>birth place</th>
- <th>current place</th>
- <th>NN</th>
- <th>#</th>
- <th>name</th>
- <th>example</th>
- <th>associations</th>
- <th>C</th>
- <th>F</th>
- <th>P</th>
- <th>T</th>
- </tr>
- </thead>
- <tbody>
- {
- data.map(({ id, personalInformation, canvas }) => {
- return canvas.map(({ form }, i) => (
- <tr
- key={i}
- onClick={() => { focusPath(id); setFocused(id) }}
- className={
- `${i === 0 ? 'main-row' : ''}
- ${id === focused ? 'data-focused' : ''}
- `
- }
- >
- {
- i === 0 ? (
- <>
- <th rowSpan={canvas.length} scope="rowGroup">{id}</th>
- <th rowSpan={canvas.length} scope="rowGroup">{VALUES.AGE[personalInformation.age]}</th>
- <th rowSpan={canvas.length} scope="rowGroup">{personalInformation.gender[0]}</th>
- <th rowSpan={canvas.length} scope="rowGroup">{personalInformation.levelEducation.map(e => VALUES.EDUCATION[e])}</th>
- <th rowSpan={canvas.length} scope="rowGroup">{personalInformation.birthPlace}</th>
- <th rowSpan={canvas.length} scope="rowGroup">{personalInformation.currentPlace}</th>
- <th rowSpan={canvas.length} scope="rowGroup">{VALUES.NON_NATIVE[personalInformation.nonNative] || '-'}</th>
- </>
- ) : null
- }
- <td>{i}</td>
- <td>{form.name}</td>
- <td>{form.soundExample || '-'}</td>
- <td>{form.associations.join(', ')}</td>
- <td>{form.correctness}</td>
- <td>{form.friendliness}</td>
- <td>{form.pleasantness}</td>
- <td>{form.trustworthiness}</td>
- </tr>
- ))
- })
- }
- </tbody>
- </Table>
- </>
- )
- }
- const FilterPanel: React.FunctionComponent<{
- applyFilters: (filters: Filters) => void
- }> = ({ applyFilters }) => {
- const [filters, setFilters] = useState<Filters>({
- ...VALUES.FILTER,
- nonNative: undefined
- });
- const [activeFilters, setActiveFilters] = useState<FilterStatus>({
- age: true,
- gender: true,
- levelEducation: true,
- nonNative: false,
- });
- const isFilterActive = (field: FilterVal) => {
- return activeFilters[field]
- };
- const activateFilter = (field: FilterVal) => ({ target }: React.ChangeEvent<HTMLInputElement>) => {
- const _filters = {
- ...activeFilters,
- [field]: target.checked
- }
-
- if (target.checked) {
- handleFilter({
- ...filters,
- [field]: VALUES.FILTER[field]
- });
- } else {
- handleFilter({
- ...filters,
- [field]: undefined
- })
- }
- setActiveFilters(_filters);
- }
- const selectAll = () => {
- handleFilter({
- ...VALUES.FILTER,
- nonNative: undefined
- })
- }
- const isChecked = (field: FilterVal, value: string) => {
- const values = filters[field];
- if (values){
- return includes(value, values);
- } else {
- return false
- }
- }
- const handleCheck = (field: FilterVal, value: string) => ({ target }: React.ChangeEvent<HTMLInputElement>) => {
- const _filters = {
- ...filters,
- [field]: target.checked ? append(value, filters[field] || []) : without([ value ], filters[field] || [])
- };
- handleFilter(_filters)
- }
- const handleFilter = (_filters: Filters) => {
- applyFilters(_filters);
- setFilters(_filters)
- }
- return (
- <div id="vom-results-filters">
- <h4>
- Filters
- <div id="vom-filter-actions">
- <Button outline size="sm" color="secondary" onClick={selectAll}>Select all</Button>
- <Button outline size="sm" color="secondary" onClick={() => handleFilter({ ...VALUES.CLEAN_FILTER })} disabled>Clear all</Button>
- </div>
- </h4>
- <div className="vom-filter-switch-group mb-3">
-
- <div className="vom-filter-switch">
- <Switch id="age-switch" checked={isFilterActive('age')} onChange={activateFilter('age')}>
- <h6>
- Age
- </h6>
- </Switch>
- <Collapse isOpen={isFilterActive('age')}>
- <FormGroup className="vom-filter-group">
- {
- (Object.keys(VALUES.AGE) as AgeVal[]).map(value => (
- <FormGroup check inline key={value}>
- <Label check>
- <Input type="checkbox" checked={isChecked('age', value)} onChange={handleCheck('age', value)}/>{VALUES.AGE[value]}
- </Label>
- </FormGroup>
- ))
- }
- </FormGroup>
- </Collapse>
- </div>
- <div className="vom-filter-switch">
- <Switch id="gender-switch" checked={isFilterActive('gender')} onChange={activateFilter('gender')}>
- <h6>Gender</h6>
- </Switch>
- <Collapse isOpen={isFilterActive('gender')}>
- <FormGroup className="vom-filter-group">
- {
- VALUES.GENDER.map(value => (
- <FormGroup check inline key={value}>
- <Label check>
- <Input disabled={!isFilterActive('gender')} type="checkbox" checked={isChecked('gender', value)} onChange={handleCheck('gender', value)}/>{value}
- </Label>
- </FormGroup>
- ))
- }
- </FormGroup>
- </Collapse>
- </div>
- <div className="vom-filter-switch">
- <Switch id="education-switch" checked={isFilterActive('levelEducation')} onChange={activateFilter('levelEducation')}>
- <h6>Level of education</h6>
- </Switch>
- <Collapse isOpen={isFilterActive('levelEducation')}>
- <FormGroup className="vom-filter-group">
- {
- (Object.keys(VALUES.EDUCATION) as EducationVal[]).map(value => (
- <FormGroup check inline key={value}>
- <Label check>
- <Input disabled={!isFilterActive('levelEducation')} type="checkbox" checked={isChecked('levelEducation', value)} onChange={handleCheck('levelEducation', value)}/>
- {VALUES.EDUCATION[value]}
- </Label>
- </FormGroup>
- ))
- }
- </FormGroup>
- </Collapse>
- </div>
- <div className="vom-filter-switch">
- <Switch id="non-native-switch" checked={isFilterActive('nonNative')} onChange={activateFilter('nonNative')}>
- <h6> Non natives </h6>
- </Switch>
- <Collapse isOpen={isFilterActive('nonNative')}>
- <FormGroup className="vom-filter-group">
- {
- (Object.keys(VALUES.NON_NATIVE) as NonNativeVal[]).map(value => (
- <FormGroup check inline key={value}>
- <Label check>
- <Input disabled={!isFilterActive('nonNative')} type="checkbox" checked={isChecked('nonNative', value)} onChange={handleCheck('nonNative', value)}/>{VALUES.NON_NATIVE[value]}
- </Label>
- </FormGroup>
- ))
- }
- </FormGroup>
- </Collapse>
- </div>
- </div>
- </div>
- )
- }
- const Switch: React.FunctionComponent<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>> = ({ id, children , ...props}) => {
- return (
- <div className="custom-control custom-switch">
- <input type="checkbox" className="custom-control-input" id={id} {...props} />
- <label className="custom-control-label" htmlFor={id}>
- { children }
- </label>
- </div>
- )
- };
- const ViewResponse: React.FunctionComponent<{response: StateData}> = ({ response }) => {
- const {
- personalInformation,
- email,
- canvas
- } = response;
- return (
- <div className="vom-view-response">
- <ListGroup>
- <ListGroupItem>
- <b>Age</b>: {VALUES.AGE[personalInformation.age]}
- </ListGroupItem>
- <ListGroupItem>
- <b>Gender</b>: {personalInformation.gender}
- </ListGroupItem>
- <ListGroupItem>
- <b>Education</b>: {personalInformation.levelEducation.map(e => VALUES.EDUCATION[e]).join(', ')}
- </ListGroupItem>
- <ListGroupItem>
- <b>Birth Place</b>: {personalInformation.birthPlace}
- </ListGroupItem>
- <ListGroupItem>
- <b>Current Place</b>: {personalInformation.currentPlace}
- </ListGroupItem>
- <ListGroupItem>
- <b>Non Native?</b>: {VALUES.NON_NATIVE[personalInformation.nonNative] || '-'}
- </ListGroupItem>
- <ListGroupItem>
- <b>email</b>: {email || '-'}
- </ListGroupItem>
- {
- canvas.map(({form}, i) => (
- <ListGroupItem key={i}>
- <b>Accent name</b>: {form.name} ({i})<br/>
- <b>Example</b>: {form.soundExample} <br/>
- <b>Associations</b>: {form.associations.join(', ')} <br/>
- <b>Correctness</b>: {form.correctness} <br/>
- <b>Friendliness</b>: {form.friendliness} <br/>
- <b>Pleasantness</b>: {form.pleasantness} <br/>
- <b>Trustworthiness</b>: {form.trustworthiness} <br/>
- </ListGroupItem>
- ))
- }
- </ListGroup>
- </div>
- )
- }
- export default Admin;
|