This commit is contained in:
Anthony Cicchetti 2020-08-29 15:15:31 -04:00
parent 0b3642e08d
commit 51dee429b7
17 changed files with 2370 additions and 142 deletions

View file

@ -1 +1 @@
14.3.0
14.8.0

View file

@ -14,9 +14,13 @@
}],
"suffix": ".bs.js",
"namespace": true,
"ppx-flags": ["decco/ppx"],
"bs-dependencies": [
"reason-react",
"bs-moment"
"bs-moment",
"bs-fetch",
"decco",
"reason-promise"
],
"refmt": 3
}

View file

@ -7,6 +7,6 @@
</head>
<body>
<div id="root" />
<script src="./bundleOutput/index.js"></script>
<script src="./dist/main.js"></script>
</body>
</html>

View file

@ -6,7 +6,10 @@
"start": "bsb -make-world -w -ws _ ",
"clean": "bsb -clean-world",
"server": "moduleserve ./ --port 8000",
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "concurrently 'yarn start' 'yarn server'",
"build:dev": "webpack --config webpack.development.js",
"build:prod": "webpack --config webpack.production.js"
},
"keywords": [
"BuckleScript",
@ -16,18 +19,27 @@
"author": "Anthony Cicchetti <me@anthonycicchetti.com>",
"license": "MIT",
"dependencies": {
"bs-fetch": "^0.6.2",
"bs-moment": "^0.4.5",
"decco": "^1.3.0",
"moment": "^2.25.3",
"react": "^16.8.6",
"react-datepicker": "^2.16.0",
"react-dom": "^16.8.6",
"reason-promise": "^1.1.1",
"reason-react": "^0.9.1",
"webpack": "^4.43.0",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12"
},
"devDependencies": {
"@babel/core": "^7.11.4",
"@babel/preset-env": "^7.11.0",
"babel-loader": "^8.1.0",
"bs-platform": "^8.1.1",
"moduleserve": "^0.9.1"
"concurrently": "^5.3.0",
"moduleserve": "^0.9.1",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.1.2"
},
"resolutions": {
"reason-crossword-front": "portal:/Users/anthonys/reason-crossword-front"

2
src/Actions.res Normal file
View file

@ -0,0 +1,2 @@
type action =
| ChangeDate(MomentRe.Moment.t)

View file

@ -1,10 +0,0 @@
[@react.component]
let make = () => {
<div className="flex one">
<DatePicker />
<ol>
<UserEntry name="Anthony" score="1:00" />
<UserEntry name="Mae" score="0:15" />
</ol>
</div>;
};

View file

@ -0,0 +1,23 @@
open Actions
type state = {date: MomentRe.Moment.t}
@react.component
let make = () => {
let (state, dispatch) = React.useReducer(
(state, action) =>
switch (action) {
| ChangeDate(newDate) => {date: newDate}
},
{date: MomentRe.momentNow()},
)
<div className="flex one">
<DatePicker currentDate=state.date updateDate=dispatch/>
<ol>
<UserEntry currentDate=state.date name="a_mae_zing" />
<UserEntry currentDate=state.date name="Anthony" />
</ol>
</div>;
};

View file

@ -1,21 +1,24 @@
open Actions
type formattedString = string;
@react.component
let make = () => {
let (date: MomentRe.Moment.t, updateDate) =
React.useState(MomentRe.momentNow);
let formatDate: MomentRe.Moment.t => formattedString =
(date: MomentRe.Moment.t) => {
let make = (~currentDate, ~updateDate) => {
let formatDate = (date) => {
date |> MomentRe.Moment.format("YYYY-MM-DD");
};
let handleChange = (event: ReactEvent.Form.t) => {
/**
let value: formattedString = ReactEvent.Form.target(event)["value"];
updateDate(_ => {value->MomentRe.momentWithFormat("YYYY-MM-DD")});
};
*/
let handleChange = (event: ReactEvent.Form.t) => {
let value = ReactEvent.Form.target(event)["value"] -> MomentRe.momentWithFormat("YYYY-MM-DD")
updateDate(ChangeDate(value))
}
<>
<input type_="date" value={formatDate(date)} onChange=handleChange />
<input type_="date" value={formatDate(currentDate)} onChange=handleChange />
</>;
};

6
src/Decode/Decode.re Normal file
View file

@ -0,0 +1,6 @@
type decodeError = [ | `DecodeError(Decco.decodeError)];
let mapDecodingError =
fun
| Ok(x) => Ok(x)
| Error(e) => Error(`DecodeError(e));

8
src/Entities.res Normal file
View file

@ -0,0 +1,8 @@
@decco type score = {
name: string,
time: string
}
let getName = (score: score) => score.name
let getTime = (score: score) => score.time
@decco type score_api_response = array<score>

View file

@ -1,5 +0,0 @@
[@react.component]
let make = (~name: string, ~score: string) =>
<article className="stack pseudo button">
{React.string(name ++ " - " ++ score)}
</article>;

View file

@ -0,0 +1,50 @@
open Entities
type state =
| LoadingScore
| ErrorFetchingScore
| LoadedScore(string)
| NoScore
@react.component
let make = (~name: string, ~currentDate: MomentRe.Moment.t) => {
let (state, setState) = React.useState(_ => LoadingScore)
let getUserScore = (scores: array<score>) : state => {
scores
-> Belt.Array.getBy((username) => name == getName(username))
-> Belt.Option.mapWithDefault(NoScore, (user_score) => LoadedScore(user_score.time))
}
React.useEffect0(() => {
open! Js.Promise
{
Fetch.fetch(j`https://acicchetti.dev/crossword/v1/${currentDate |> MomentRe.Moment.format("YYYY-MM-DD")}`)
|> then_(Fetch.Response.json)
|> then_(text =>
score_api_response_decode(text)
-> Belt.Result.mapWithDefault(ErrorFetchingScore, (x) => x |> getUserScore)
-> (newScore => setState(_oldState => newScore))
-> resolve
)
|> catch(_err => {
setState(_previousState => ErrorFetchingScore)
-> resolve
})
|> ignore
}
None
})
<article className="stack pseudo button">
{React.string(j`${name} - ${
switch (state) {
| LoadingScore => "Loading"
| ErrorFetchingScore => "Error Fetching Score"
| LoadedScore(score) => score
| NoScore => "No Score"
}
}`)
}
</article>
}

25
webpack.common.js Normal file
View file

@ -0,0 +1,25 @@
const path = require('path');
const DIST_DIR = path.resolve(__dirname, "dist");
const SRC_DIR = path.resolve(__dirname, "src");
module.exports = {
entry: {
main: SRC_DIR + '/Index.bs.js',
},
output: {
path: DIST_DIR,
filename: '[name].js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
};

View file

@ -1,14 +0,0 @@
const path = require('path');
module.exports = {
entry: './src/Index.bs.js',
// If you ever want to use webpack during development, change 'production'
// to 'development' as per webpack documentation. Again, you don't have to
// use webpack or any other bundler during development! Recheck README if
// you didn't know this
mode: 'production',
output: {
path: path.join(__dirname, "bundleOutput"),
filename: 'index.js',
},
};

13
webpack.development.js Normal file
View file

@ -0,0 +1,13 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
host: 'localhost',
port: 7000,
open: true,
},
watch: true
})

7
webpack.production.js Normal file
View file

@ -0,0 +1,7 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
})

2300
yarn.lock

File diff suppressed because it is too large Load diff