Skip to content

Commit

Permalink
Split components
Browse files Browse the repository at this point in the history
  • Loading branch information
marlonbaeten committed May 24, 2024
1 parent 57f4e7a commit 68999dc
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 65 deletions.
72 changes: 8 additions & 64 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Fragment } from 'react/jsx-runtime';
import rawData from './data.json';
import Table from './Table';
import usePersistence, { PersistenceContext } from './usePersistence';

const data = rawData as unknown as {
[theme: string]: {
Expand All @@ -16,9 +17,11 @@ const levels = [
'meermaals zelfstandig uitgevoerd',
];

function App() {
export default function App(): JSX.Element {
const persistence = usePersistence();

return (
<div>
<PersistenceContext.Provider value={persistence}>
<h1>Ervaringskompas</h1>
<p>
Welke ervaring heb je opgedaan met deze beroepsactiviteit in de praktijk
Expand All @@ -32,66 +35,7 @@ function App() {
))}
</ol>
</div>
<table>
<thead>
<tr>
<th colSpan={2}></th>
{levels.map((level, levelIndex) => (
<th key={level}>{levelIndex + 1}</th>
))}
</tr>
</thead>
<tbody>
{Object.entries(data).map(([theme, { color, items }], themeIndex) => (
<Fragment key={theme}>
<tr key={theme}>
<td style={{ borderBottomColor: color }}></td>
<th style={{ borderBottomColor: color }} colSpan={6}>
<h3 style={{ borderColor: color }}>
<span style={{ background: color }}>{themeIndex + 1}</span>
{theme}
</h3>
</th>
</tr>
{items.map((item, index) => (
<tr key={item} className="selectable">
<td style={{ borderBottomColor: color }}>
<label htmlFor={`check-${index}`} title="markeren">
<input
type="checkbox"
id={`check-${index}`}
name={`check-${index}`}
/>
</label>
</td>
<th scope="row" style={{ borderBottomColor: color }}>
{item}
</th>
{levels
.map((level, levelIndex) => ({
level,
key: `option-${index}-${levelIndex}`,
}))
.map(({ level, key }, levelIndex) => (
<td key={level} style={{ borderBottomColor: color }}>
<label htmlFor={key} title={level}>
<input
type="radio"
name={`option-${index}`}
id={key}
value={levelIndex}
/>
</label>
</td>
))}
</tr>
))}
</Fragment>
))}
</tbody>
</table>
</div>
<Table levels={levels} themes={Object.entries(data)} />
</PersistenceContext.Provider>
);
}

export default App;
51 changes: 51 additions & 0 deletions src/Item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
interface ItemProps {
name: string;
index: number;
color: string;
levels: string[];
selected: number;
onSelect: (level: number) => void;
}

export default function Item({ name, index, color, levels, selected, onSelect }: ItemProps): JSX.Element {
return (
<tr className="selectable">
<td style={{ borderBottomColor: color, borderLeftColor: color }}>
<label htmlFor={`check-${index}`} title="markeren">
<input
type="checkbox"
id={`check-${index}`}
name={`check-${index}`}
/>
</label>
</td>
<th scope="row" style={{ borderBottomColor: color }}>
{name}
</th>
{levels
.map((level, levelIndex) => ({
level,
key: `option-${index}-${levelIndex}`,
}))
.map(({ level, key }, levelIndex) => (
<td
key={level}
style={{
borderBottomColor: color,
borderRightColor: levelIndex === levels.length - 1 ? color : undefined
}}>
<label htmlFor={key} title={level}>
<input
type="radio"
name={`option-${index}`}
id={key}
value={levelIndex}
onChange={() => onSelect(levelIndex)}
checked={levelIndex === selected}
/>
</label>
</td>
))}
</tr>
);
}
28 changes: 28 additions & 0 deletions src/Table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Theme from './Theme';

interface TableProps {
themes: [string, { color: string; items: string[] }][];
levels: string[];
}

export default function Table({ levels, themes }: TableProps): JSX.Element {
return (
<table>
<thead>
<tr>
<th colSpan={2} style={{ border: 'none' }}></th>
{levels.map((level, levelIndex) => (
<th key={level}>{levelIndex + 1}</th>
))}
</tr>
</thead>
<tbody>
{themes
.map(([name, { color, items }], index) => ({ name, color, items, index }))
.map((theme) => (
<Theme key={theme.name} theme={theme} levels={levels} />
))}
</tbody>
</table>
);
}
50 changes: 50 additions & 0 deletions src/Theme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Fragment, useContext } from 'react';
import Item from './Item';
import { PersistenceContext } from './usePersistence';

interface ThemeProps {
theme: {
name: string;
color: string;
items: string[];
index: number;
};
levels: string[];
}

export default function Theme({
theme: { name, color, items, index: themeIndex },
levels,
}: ThemeProps): JSX.Element {
const { getLevel, select } = useContext(PersistenceContext);

return (
<Fragment>
<tr>
<th
style={{
borderBottomColor: color,
}}
colSpan={7}
className="theme"
>
<h3>
<span style={{ background: color }}>{themeIndex + 1}</span>
{name}
</h3>
</th>
</tr>
{items.map((item, index) => (
<Item
key={item}
name={item}
index={index}
levels={levels}
color={color}
selected={getLevel(themeIndex, index)}
onSelect={(level: number) => select(themeIndex, index, level)}
/>
))}
</Fragment>
);
}
24 changes: 23 additions & 1 deletion src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
html {
box-sizing: border-box;
font-size: 16px;
min-width: 470px;
}

*, *:before, *:after {
Expand Down Expand Up @@ -33,6 +34,12 @@ body {
padding: 2rem;
}

@media screen and (max-width: 768px) {
body {
padding: 1rem;
}
}

h1 {
font-size: 2rem;
margin-bottom: 1rem;
Expand All @@ -57,6 +64,10 @@ ol {
background-color: #fafafa;
}

.legenda h2 {
margin-bottom: 0.5rem;
}

/* table styling */

table {
Expand All @@ -71,13 +82,19 @@ tbody th {
padding: 0.5rem;
}

th.theme {
border: none;
border-bottom: 1px solid #000;
}

tbody td {
width: 50px;
}

td, th {
border: 1px solid #eaeaea;
border: 1px solid #f0f0f0;
vertical-align: middle;
min-width: 2rem;
}

tbody td label {
Expand All @@ -88,6 +105,10 @@ tbody td label {
cursor: pointer;
}

table h3 {
margin-top: 1rem;
}

table h3 span {
display: inline-block;
width: 2rem;
Expand All @@ -96,6 +117,7 @@ table h3 span {
text-align: center;
border-radius: 1rem;
margin-right: 1rem;
color: #fff;
}

tbody input {
Expand Down
44 changes: 44 additions & 0 deletions src/usePersistence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { createContext, useEffect, useReducer } from 'react';

type Action = { type: 'select'; theme: number; item: number; level: number };

type State = { [key: string]: number };

function reducer(state: State, action: Action) {
switch (action.type) {
case 'select':
return { ...state, [`${action.theme}-${action.item}`]: action.level };
default:
throw new Error();
}
}

interface PersistenceState {
getLevel: (theme: number, item: number) => number;
select: (theme: number, item: number, level: number) => void;
}

function initialState(): State {
const localState = window.localStorage.getItem('persistence');

return localState ? JSON.parse(localState) : {};
}

export const PersistenceContext = createContext<PersistenceState>({
getLevel: () => 0,
select: () => {},
});

export default function usePersistence(): PersistenceState {
const [state, dispatch] = useReducer(reducer, [], initialState);

useEffect(() => {
window.localStorage.setItem('persistence', JSON.stringify(state));
}, [state]);

return {
getLevel: (theme: number, item: number) => state[`${theme}-${item}`],
select: (theme: number, item: number, level: number) =>
dispatch({ type: 'select', theme, item, level }),
};
}

0 comments on commit 68999dc

Please sign in to comment.