<todo-create></todo-create>
<todo-list></todo-list>
import {realtimeRestModel, DefineMap, DefineList, Component, fixture} from "//unpkg.com/can@5/core.mjs";

const Todo = DefineMap.extend("Todo",{
    id: { type: "number", identity: true },
    complete: { type: "boolean", default: false },
    dueDate: {type: "date", Default: Date},
    name: "string",
    preventSave(){
        return !this.name || this.isSaving() || this.isDestroying();
    }
});

Todo.List = DefineList.extend("TodoList",{
    "#": Todo
});

const todoConnection = realtimeRestModel({
    Map: Todo,
    List: Todo.List,
    url: "/api/todos/{id}"
});

mockService();

Component.extend({
    tag: "todo-list",
    view: `
    Sort By: <select value:bind="sort">
        <option value="">none</option>
        <option value="name">name</option>
        <option value="dueDate">dueDate</option>
    </select>

    Show: <select value:bind="completeFilter">
        <option value="">All</option>
        <option value="complete">Complete</option>
        <option value="incomplete">Incomplete</option>
    </select>

    Due: <select value:bind="dueFilter">
        <option value="">Anytime</option>
        <option value="today">Today</option>
        <option value="week">This Week</option>
    </select>

    Results <select value:bind="count">
        <option value="">All</option>
        <option value="10">10</option>
        <option value="20">20</option>
    </select>

    <ul>
        {{# if(todosPromise.isResolved) }}
            {{# for(todo of todosPromise.value) }}
                <li>
                    <input type='checkbox'
                        checked:bind='todo.complete'
                        on:change="todo.save()"
                        disabled:from="todo.preventSave()"/>
                    <label>{{ todo.name }}</label>
                    <input type='date'
                        valueAsDate:bind='todo.dueDate'
                        on:change="todo.save()"
                        disabled:from="todo.preventSave()"/>
                    <button on:click="todo.destroy()"
                        disabled:from="todo.preventSave()">delete</button>
                </li>
            {{/ for }}
        {{/ if }}
        {{# if(todosPromise.isPending) }}
            <li>Loading</li>
        {{/ if }}
    </ul>
    `,
    ViewModel: {
        sort: "string",
        completeFilter: "string",
        dueFilter: "string",
        count: {type:"string", default: "10"},
        todosPromise: {
            get(){
                var query = {filter: { }};
                if(this.sort) {
                    query.sort =  this.sort;
                }
                if(this.completeFilter) {
                    query.filter.complete = this.completeFilter === "complete";
                }
                if(this.dueFilter) {
                    var day = 24*60*60*1000;
                    var now = new Date();
                    var today = new Date(now.getFullYear(), now.getMonth(), now.getDate() );
                    if(this.dueFilter === "today") {

                        query.filter.dueDate = {
                            $gte: now.toString(),
                            $lt: new Date(now.getTime() + day).toString()
                        }
                    }
                    if(this.dueFilter === "week") {
                        var start = today.getTime() - (today.getDay() * day);
                        query.filter.dueDate = {
                            $gte: new Date(start).toString(),
                            $lt: new Date(start + 7*day).toString()
                        };
                    }
                }
                if(this.count) {
                    query.page = {
                        start: 0,
                        end: (+this.count)-1
                    };
                }
                return Todo.getList(query);
            }
        }
    }
});

Component.extend({
    tag: "todo-create",
    view: `
        <form on:submit="createTodo(scope.event)">
            <p>
                <label>Name</label>
                <input on:input:value:bind='todo.name'/>
            </p>
            <p>
                <label>Complete</label>
                <input type='checkbox' checked:bind='todo.complete'/>
            </p>
            <p>
                <label>Date</label>
                <input type='date' valueAsDate:bind='todo.dueDate'/>
            </p>
            <button disabled:from="todo.preventSave()">Create Todo</button>
            {{# if(todo.isSaving()) }}Creating ....{{/ if }}
        </form>
    `,
    ViewModel: {
        todo: {
            Default: Todo
        },
        createTodo(event) {
            event.preventDefault();
            this.todo.save().then((createdTodo) => {
                this.todo = new Todo();
            })
        }
    }
});

function mockService(){
	var terms = ["can you","please","","","",""],
	    verbs = ["clean","walk","do","vaccum","organize","fold","wash","dust","pay","cook","get","take out"],
	    subjects = ["dog","laundry","diapers","clothes","car","windows","carpet","taxes","food","gas","trash"];

	var dayInMS = 24*60*60*1000;
	var lastWeek = new Date() - (7*dayInMS);
	var fourWeeks = new Date().getTime() + (4*7*dayInMS);

	var todoStore = fixture.store(100, function(){
	    return {
	        complete: fixture.rand([true, false],1)[0],
	        dueDate: new Date( fixture.rand(lastWeek, fourWeeks) ).toString(),
	        name: (fixture.rand(terms,1)[0]+" "+fixture.rand(verbs,1)[0]+" "+fixture.rand(subjects,1)[0]).trim()
	    }
	}, Todo);

	fixture("/api/todos/{id}", todoStore);
	fixture.delay = 500;
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.