Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(demo): save tasks in demo and Collection (#511)
* WIP: refactor collections * WIP: fix project bugs * WIP: save tasks to firebase * WIP: change tasks implementation * WIP: saves running task and updates ui with elapsed * WIP: moving some computed to Collection, path changes * WIP: prevent updateNow from retrigger * WIP: add contributors * WIP: fix saving running task * WIP: fixed bugs, better UI * WIP: keep header visible during login * WIP: move firebase settings in its own file, add README * WIP: should auto start running task * WIP: remove unused images, change favicon * WIP: allow anonymous login * WIP: fix bug when project is not saved * WIP: use visibility api to stop time passing when hidden
- Loading branch information
Showing
122 changed files
with
1,469 additions
and
880 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Cerebral-Demo | ||
|
||
This application is a simple time-tracker built with `cerebral`, `cerebral-provider-firebase`, `cerebral-forms` and `cerebral-router`. It serves as an example on how all these modules work together to create a complete application with relational data, login, time based events and so on. | ||
|
||
This project is an ongoing community effort so if you feel like you could add some features, please join in ! | ||
|
||
|
||
## Firebase setup | ||
|
||
In case you want to run this application on your own firebase project, please follow the following steps: | ||
|
||
### Config | ||
|
||
Copy the `web app` config data from the firebase console into `src/firebaseConfig.js`. | ||
|
||
### Authentification | ||
|
||
Enable `email/password` authentification in the firebase console. | ||
|
||
### Security rules | ||
|
||
Set these security rules in the database section of the firebase console: | ||
|
||
```js | ||
{ | ||
"rules": { | ||
"$uid": { | ||
"clients": { | ||
".indexOn": "updated_at" | ||
}, | ||
"projects": { | ||
".indexOn": "updated_at" | ||
}, | ||
"tasks": { | ||
".indexOn": "updated_at" | ||
}, | ||
".read": "auth != null && $uid == auth.uid", | ||
".write": "auth != null && $uid == auth.uid" | ||
}, | ||
".read": false, | ||
".write": false | ||
} | ||
} | ||
``` | ||
|
||
## Start application | ||
|
||
Once the dependencies are installed, start the application with: | ||
|
||
``` | ||
npm run start | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,13 @@ | ||
* Up/down arrows in project selector should select projects in current selector list. | ||
* user info in menu (with logout link) | ||
* enable Report page with url query for filtering by client/project/date, etc | ||
* showSaveDraftModal for project | ||
* on update of client website url, add missing 'http://' if needed and in Client/index.js and Client/form.js, remove adding http:// | ||
* refuse to delete project with tasks or move tasks to no-project. | ||
* refuse to delete client with projects or move projects to no-client. | ||
* Create (dark) footer with links to cerebral stuff and language selector. | ||
* Tasks component to search for tasks.., not sure what should go there. | ||
|
||
* @julio ? implement sendEmailVerification | ||
and applyActionCode | ||
|
||
* @gaspard edit/delete tasks... | ||
* @gaspard fix editing name of running task (it is saved and the `updated` call changes the field the user is currently typing in). Should prevent updates to forms field when it is focussed. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
26 changes: 26 additions & 0 deletions
26
packages/demo/src/common/Collection/computed/visibleKeys.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import {Computed} from 'cerebral' | ||
import paths from '../paths' | ||
import sort from '../sort' | ||
|
||
export default function (moduleName) { | ||
const {collectionPath, draftPath, filterPath} = paths(moduleName) | ||
|
||
return Computed( | ||
{ | ||
items: `${collectionPath}.**`, | ||
afilter: filterPath, | ||
selectedKey: `${draftPath}.key` | ||
}, | ||
({items, afilter, selectedKey}) => { | ||
const filter = afilter && afilter.toLowerCase() | ||
const list = Object.keys(items).filter(key => ( | ||
!filter || items[key].name.toLowerCase().indexOf(filter) >= 0 | ||
)) | ||
if (selectedKey && list.indexOf(selectedKey) < 0) { | ||
// Always show edited item (also if it is not saved yet) | ||
list.unshift(selectedKey) | ||
} | ||
return list.sort(sort) | ||
} | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import init from './signals/init' | ||
import create from './signals/create' | ||
import discardDraft from './signals/discardDraft' | ||
import edit from './signals/edit' | ||
import newItem from './signals/newItem' | ||
import update from './signals/update' | ||
import updated from './signals/updated' | ||
import updateDraft from './signals/updateDraft' | ||
import updateFilter from './signals/updateFilter' | ||
import remove from './signals/remove' | ||
import removed from './signals/removed' | ||
|
||
export default function collection (moduleName, initState) { | ||
return { | ||
create: create(moduleName), | ||
discardDraft: discardDraft(moduleName), | ||
edit: edit(moduleName), | ||
init: init(moduleName, initState), | ||
newItem: newItem(moduleName), | ||
update: update(moduleName), | ||
updated: updated(moduleName), | ||
remove: remove(moduleName), | ||
removed: removed(moduleName), | ||
updateFilter: updateFilter(moduleName), | ||
updateDraft: updateDraft(moduleName) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import {v4} from 'uuid' | ||
|
||
export default function (context) { | ||
return {value: v4()} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import {input, set, state, string, when} from 'cerebral/operators' | ||
|
||
export default function paths (moduleName) { | ||
return { | ||
collectionPath: `${moduleName}.all`, | ||
draftPath: `${moduleName}.$draft`, | ||
filterPath: `${moduleName}.$filter`, | ||
errorPath: `app.$error`, | ||
dynamicPaths: [ | ||
set( | ||
input`remoteCollectionPath`, string`${state`user.$currentUser.uid`}.${moduleName}` | ||
), | ||
when(input`key`), { | ||
true: [ | ||
set( | ||
input`itemPath`, string`${moduleName}.all.${input`key`}` | ||
), | ||
set( | ||
input`remoteItemPath`, | ||
string`${input`remoteCollectionPath`}.${input`key`}` | ||
) | ||
], | ||
false: [] | ||
} | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import visibleKeys from '../computed/visibleKeys' | ||
import paths from '../paths' | ||
|
||
export default function connectProps (moduleName) { | ||
const {draftPath, filterPath} = paths(moduleName) | ||
return { | ||
visibleKeys: visibleKeys(moduleName), | ||
filter: filterPath, | ||
selectedKey: `${draftPath}.key` | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import newItem from './newItem' | ||
import update from './update' | ||
|
||
export default function (moduleName) { | ||
return [ | ||
...newItem(moduleName), | ||
...update(moduleName) | ||
] | ||
} |
10 changes: 10 additions & 0 deletions
10
packages/demo/src/common/Collection/signals/discardDraft.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {state, unset} from 'cerebral/operators' | ||
import paths from '../paths' | ||
|
||
export default function (moduleName) { | ||
const {draftPath} = paths(moduleName) | ||
return [ | ||
unset(state`${draftPath}.key`), | ||
unset(state`${draftPath}`) | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import {input, set, state} from 'cerebral/operators' | ||
import paths from '../paths' | ||
|
||
export default function (moduleName) { | ||
const {draftPath, dynamicPaths} = paths(moduleName) | ||
return [ | ||
dynamicPaths, | ||
set(state`${draftPath}`, state`${input`itemPath`}`), | ||
// To trigger change on collection list listening for | ||
// draft.key | ||
set(state`${draftPath}.key`, input`key`) | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import {input, merge, set, state, when} from 'cerebral/operators' | ||
import {onChildAdded, onChildChanged, onChildRemoved, value} from 'cerebral-provider-firebase' | ||
import paths from '../paths' | ||
|
||
let timestamp | ||
|
||
export default function init (moduleName, initState = {}) { | ||
const {collectionPath, dynamicPaths, errorPath} = paths(moduleName) | ||
return [ | ||
// prepare remote and local path | ||
...dynamicPaths, | ||
() => { | ||
// timestamp before calling value | ||
timestamp = (new Date()).getTime() | ||
}, | ||
value(input`remoteCollectionPath`), { | ||
success: [ | ||
// need to use 'merge' here to notify changes on default item keys | ||
merge(state`${collectionPath}`, initState), | ||
when(input`value`), { | ||
true: [ | ||
merge(state`${collectionPath}`, input`value`) | ||
], | ||
false: [] | ||
}, | ||
// start listening | ||
onChildAdded( | ||
input`remoteCollectionPath`, `${moduleName}.updated`, | ||
{ | ||
orderByChild: 'updated_at', | ||
// Use the timestamp set before getting value | ||
startAt: () => ({value: timestamp}) | ||
} | ||
), | ||
onChildChanged( | ||
input`remoteCollectionPath`, `${moduleName}.updated`), | ||
onChildRemoved( | ||
input`remoteCollectionPath`, `${moduleName}.removed`) | ||
], | ||
error: [ | ||
set(state`${errorPath}`, input`error`) | ||
] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import {merge, set, state} from 'cerebral/operators' | ||
import makeRef from '../operators/makeRef' | ||
import paths from '../paths' | ||
|
||
export default function (moduleName) { | ||
const {draftPath, filterPath} = paths(moduleName) | ||
return [ | ||
// Prepare initial item state | ||
set(state`${draftPath}`, {}), | ||
merge(state`${draftPath}`, { | ||
key: makeRef, | ||
name: state`${filterPath}` | ||
}) | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import {input} from 'cerebral/operators' | ||
import {remove} from 'cerebral-provider-firebase' | ||
import paths from '../paths' | ||
|
||
export default function (moduleName) { | ||
const {dynamicPaths} = paths(moduleName) | ||
return [ | ||
...dynamicPaths, | ||
remove(input`remoteItemPath`), { | ||
success: [], | ||
error: [] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {input, state, unset} from 'cerebral/operators' | ||
import paths from '../paths' | ||
|
||
export default function (moduleName) { | ||
const {dynamicPaths} = paths(moduleName) | ||
return [ | ||
...dynamicPaths, | ||
unset(state`${input`itemPath`}`) | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import {input, set} from 'cerebral/operators' | ||
import {set as setRemote} from 'cerebral-provider-firebase' | ||
import paths from '../paths' | ||
import timestampValue from './timestampValue' | ||
|
||
export default function (moduleName) { | ||
const {dynamicPaths} = paths(moduleName) | ||
return [ | ||
// Expects input.key and input.value | ||
// Ensure value.key is properly set. | ||
set(input`value.key`, input`key`), | ||
...timestampValue, | ||
...dynamicPaths, | ||
setRemote(input`remoteItemPath`, input`value`) | ||
// This chain must be followed by {success: [], error: []} | ||
] | ||
} |
11 changes: 11 additions & 0 deletions
11
packages/demo/src/common/Collection/signals/timestampValue.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export default [ | ||
function timestampValue ({input: {value}}) { | ||
return {value: Object.assign( | ||
{}, | ||
{created_at: {'.sv': 'timestamp'}}, | ||
value, | ||
{updated_at: {'.sv': 'timestamp'}} | ||
) | ||
} | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import {input, set, state, unset} from 'cerebral/operators' | ||
import paths from '../paths' | ||
import save from './save' | ||
|
||
export default function (moduleName) { | ||
const {draftPath, errorPath} = paths(moduleName) | ||
const p = [ | ||
set(input`key`, state`${draftPath}.key`), | ||
set(input`value`, state`${draftPath}`), | ||
...save(moduleName), { | ||
success: [ | ||
// Clear form. | ||
unset(state`${draftPath}.key`) | ||
], | ||
error: [ | ||
set(state`${errorPath}`, input`error`) | ||
] | ||
} | ||
] | ||
return p | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import {input, set, state} from 'cerebral/operators' | ||
import paths from '../paths' | ||
|
||
export default function (moduleName) { | ||
const {draftPath} = paths(moduleName) | ||
return [ | ||
set(state`${draftPath}.${input`key`}`, input`value`) | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import {input, set, state} from 'cerebral/operators' | ||
import paths from '../paths' | ||
|
||
export default function (moduleName) { | ||
const {filterPath} = paths(moduleName) | ||
return [ | ||
set(state`${filterPath}`, input`value`) | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import {input, set, state, when} from 'cerebral/operators' | ||
import paths from '../paths' | ||
|
||
export default function (moduleName) { | ||
const {draftPath, dynamicPaths} = paths(moduleName) | ||
|
||
return [ | ||
...dynamicPaths, | ||
|
||
set(state`${input`itemPath`}`, input`value`), | ||
|
||
when(state`${draftPath}.key`, input`key`, | ||
(draftKey, updatedKey) => draftKey === updatedKey | ||
), { | ||
true: [ | ||
set(state`${draftPath}`, input`value`) | ||
], | ||
false: [] | ||
} | ||
] | ||
} |
Oops, something went wrong.