Skip to content

Commit

Permalink
uploading and downloading paterns
Browse files Browse the repository at this point in the history
  • Loading branch information
slawomirzaba committed Jan 23, 2019
1 parent ec9b0dc commit f803b88
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 18 deletions.
14 changes: 14 additions & 0 deletions src/modules/Common/lib/download.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const download = (data: string, filename: string, type: string) => {
const file = new Blob([data], { type: type });

const a = document.createElement("a");
const url = URL.createObjectURL(file);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
});
};
5 changes: 5 additions & 0 deletions src/modules/Common/lib/downloadJson.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { download } from "./download";

export const downloadJson = (data: string, fileName: string) => {
download(data, fileName, "application/json");
};
2 changes: 2 additions & 0 deletions src/modules/Common/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { downloadJson } from "./downloadJson";
export { uploadFile } from "./uploadFile";
11 changes: 11 additions & 0 deletions src/modules/Common/lib/uploadFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const uploadFile = (file: File, onSuccess: (data: string) => void) => {
const reader = new FileReader();
reader.onload = (e: any) => {
try {
onSuccess(e.target.result);
} catch (ex) {
alert("Problem with loading file");
}
};
reader.readAsText(file);
};
10 changes: 8 additions & 2 deletions src/modules/Game/Components/Board/Board.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { RefObject, ChangeEvent } from "react";
import { times as _times } from "lodash";
import "./board.css";
import { Element } from "../Element";
Expand All @@ -22,6 +22,8 @@ interface PropsI {
onMouseUpBoard: () => void;
onMouseLeaveBoard: () => void;
toggleBorders: () => void;
saveConfiguration: () => void;
handleUploadFile: (event: ChangeEvent<HTMLInputElement>) => void;
}

export const Board = ({
Expand All @@ -38,7 +40,9 @@ export const Board = ({
onMouseDownElement,
onMouseUpBoard,
onMouseLeaveBoard,
toggleBorders
toggleBorders,
saveConfiguration,
handleUploadFile
}: PropsI) => {
return (
<div className="board">
Expand Down Expand Up @@ -75,6 +79,8 @@ export const Board = ({
isPlayEnabled={isPlayEnabled}
clearBoard={clearBoard}
toggleBorders={toggleBorders}
saveConfiguration={saveConfiguration}
handleUploadFile={handleUploadFile}
/>
</tfoot>
</table>
Expand Down
34 changes: 32 additions & 2 deletions src/modules/Game/Components/TableFooter/TableFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { ChangeEvent, useRef } from "react";
import "./tableFooter.css";

interface PropsI {
Expand All @@ -9,6 +9,8 @@ interface PropsI {
pauseAction: () => void;
clearBoard: () => void;
toggleBorders: () => void;
saveConfiguration: () => void;
handleUploadFile: (event: ChangeEvent<HTMLInputElement>) => void;
}

export const TableFooter = ({
Expand All @@ -18,8 +20,16 @@ export const TableFooter = ({
executeOneIteration,
pauseAction,
clearBoard,
toggleBorders
toggleBorders,
saveConfiguration,
handleUploadFile
}: PropsI) => {
const inputUploadRef = useRef(null);

const clearUploadFileValue = () => {
inputUploadRef.current.value = "";
};

return (
<tr>
<td colSpan={tableColumns} className="board__tableFooter">
Expand All @@ -41,6 +51,26 @@ export const TableFooter = ({
<button onClick={toggleBorders}>
<i className="fas fa-th" />
</button>
<button onClick={saveConfiguration} disabled={isPlayEnabled}>
<i className="fas fa-save" />
</button>
<label
htmlFor="pattern-upload"
className={`board__uploadFileLabel ${
isPlayEnabled ? "board__uploadFileLabel--disabled" : ""
}`}
>
<i className="fas fa-upload" />
</label>
<input
id="pattern-upload"
type="file"
ref={inputUploadRef}
className="board__uploadFileInput"
onChange={handleUploadFile}
disabled={isPlayEnabled}
onClick={clearUploadFileValue}
/>
</td>
</tr>
);
Expand Down
12 changes: 9 additions & 3 deletions src/modules/Game/Components/TableFooter/tableFooter.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
border: 1px solid #777;
}

.board__tableFooter>button {
.board__tableFooter>button,
.board__tableFooter>.board__uploadFileLabel {
background: transparent;
border: none;
margin: 0;
Expand All @@ -18,11 +19,16 @@
opacity: 0.7;
}

.board__tableFooter>button:not([disabled]):hover {
.board__tableFooter>button:not([disabled]):hover,
.board__tableFooter>.board__uploadFileLabel:not(.board__uploadFileLabel--disabled):hover {
opacity: 1;
}

.board__tableFooter>button:disabled {
.board__tableFooter>button:disabled,
.board__tableFooter>.board__uploadFileLabel--disabled {
cursor: not-allowed;
}

.board__uploadFileInput {
display: none;
}
43 changes: 36 additions & 7 deletions src/modules/Game/Container/Container.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, ChangeEvent } from "react";
import { times as _times } from "lodash";
import { ActiveElementsKeysI, PatternI, SliderConfigI } from "../interfaces";
import { Header } from "../Components/Header";
import { Board } from "../Components/Board";
import "./game.css";
import { getCellKey, getNewCellState } from "../lib";
import { usePositiveInteger, useToggle } from "../hooks";
import { downloadJson, uploadFile } from "../../Common/lib";

export const Container = () => {
const DEFAULT_SLIDER_TIME_VALUE = 3;
Expand Down Expand Up @@ -88,8 +89,8 @@ export const Container = () => {
const minColumns = pattern.minColumns || INITIAL_COLUMNS_NUMBER;
const minRows = pattern.minRows || INITIAL_ROWS_NUMBER;

setColumns(minColumns);
setRows(minRows);
if (minColumns > columns) setColumns(minColumns);
if (minRows > rows) setRows(minRows);
setActiveElementsKeys(pattern.structure);
};

Expand Down Expand Up @@ -122,10 +123,15 @@ export const Container = () => {
...activeElementsKeys
};

_times(rows + 10).forEach(rowIndex => {
_times(columns + 10).forEach(columnIndex => {
const key = getCellKey(rowIndex - 5, columnIndex - 5);
const newCellValue = getNewCellState(key, currentActiveElementsKeys);
_times(rows).forEach(rowIndex => {
_times(columns).forEach(columnIndex => {
const key = getCellKey(rowIndex, columnIndex);
const newCellValue = getNewCellState(
key,
rows,
columns,
currentActiveElementsKeys
);

if (newCellValue === Boolean(activeElementsKeys[key])) return;

Expand All @@ -143,6 +149,27 @@ export const Container = () => {
}
};

const saveConfiguration = (): void => {
const data: Partial<PatternI> = {
structure: activeElementsKeys,
minColumns: columns,
minRows: rows
};
downloadJson(JSON.stringify(data), "myPattern.json");
};

const onSuccessFileUpload = (data: string): void => {
const pattern: Partial<PatternI> = JSON.parse(data);
setColumns(pattern.minColumns);
setRows(pattern.minRows);
setActiveElementsKeys(pattern.structure);
};

const handleUploadFile = (event: ChangeEvent<HTMLInputElement>): void => {
const file = event.target.files[0];
uploadFile(file, onSuccessFileUpload);
};

return (
<div className="game">
<Header
Expand Down Expand Up @@ -172,6 +199,8 @@ export const Container = () => {
onMouseUpBoard={onMouseUpBoard}
onMouseLeaveBoard={onMouseLeaveBoard}
toggleBorders={toggleBorders}
saveConfiguration={saveConfiguration}
handleUploadFile={handleUploadFile}
/>
</div>
);
Expand Down
11 changes: 9 additions & 2 deletions src/modules/Game/lib/countActiveNeighbors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@ import { getCellKey } from "./getCellKey";

export const countActiveNeighbors = (
cellKey: string,
rowsNumber: number,
columnsNumber: number,
activeElementsKeys: ActiveElementsKeysI
): number => {
let neighbours = 0;
const [cellRowNumber, cellColumnNumber] = cellKey
.split(",")
.map((element: string) => parseInt(element, 10));

for (let i = cellRowNumber - 1; i <= cellRowNumber + 1; ++i) {
for (let j = cellColumnNumber - 1; j <= cellColumnNumber + 1; ++j) {
const firstRowToCheck = Math.max(cellRowNumber - 1, 0);
const lastRowToCheck = Math.min(cellRowNumber + 1, rowsNumber);
const firstColumnToCheck = Math.max(cellColumnNumber - 1, 0);
const lastColumnToCheck = Math.min(cellColumnNumber + 1, columnsNumber);

for (let i = firstRowToCheck; i <= lastRowToCheck; ++i) {
for (let j = firstColumnToCheck; j <= lastColumnToCheck; ++j) {
const key = getCellKey(i, j);
if (key !== cellKey && activeElementsKeys[key]) neighbours++;
}
Expand Down
9 changes: 8 additions & 1 deletion src/modules/Game/lib/getNewCellState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ import { countActiveNeighbors } from ".";

export const getNewCellState = (
cellKey: string,
rowsNumber: number,
columnsNumber: number,
activeElementsKeys: ActiveElementsKeysI
): boolean => {
const isActiveCell = activeElementsKeys[cellKey];
const neighborsCount = countActiveNeighbors(cellKey, activeElementsKeys);
const neighborsCount = countActiveNeighbors(
cellKey,
rowsNumber,
columnsNumber,
activeElementsKeys
);

if (isActiveCell && neighborsCount < 2) return false;
if (isActiveCell && neighborsCount > 3) return false;
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"noEmit": true,
"jsx": "preserve",
"resolveJsonModule": true,
"suppressImplicitAnyIndexErrors": true
"suppressImplicitAnyIndexErrors": true,
"strictNullChecks": false,
},
"include": [
"src"
Expand Down

0 comments on commit f803b88

Please sign in to comment.