AppToDoList
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
19
.meteor/.finished-upgraders
Normal file
19
.meteor/.finished-upgraders
Normal file
@@ -0,0 +1,19 @@
|
||||
# This file contains information which helps Meteor properly upgrade your
|
||||
# app when you run 'meteor update'. You should check it into version control
|
||||
# with your project.
|
||||
|
||||
notices-for-0.9.0
|
||||
notices-for-0.9.1
|
||||
0.9.4-platform-file
|
||||
notices-for-facebook-graph-api-2
|
||||
1.2.0-standard-minifiers-package
|
||||
1.2.0-meteor-platform-split
|
||||
1.2.0-cordova-changes
|
||||
1.2.0-breaking-changes
|
||||
1.3.0-split-minifiers-package
|
||||
1.4.0-remove-old-dev-bundle-link
|
||||
1.4.1-add-shell-server-package
|
||||
1.4.3-split-account-service-packages
|
||||
1.5-add-dynamic-import-package
|
||||
1.7-split-underscore-from-meteor-base
|
||||
1.8.3-split-jquery-from-blaze
|
||||
1
.meteor/.gitignore
vendored
Normal file
1
.meteor/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
local
|
||||
7
.meteor/.id
Normal file
7
.meteor/.id
Normal file
@@ -0,0 +1,7 @@
|
||||
# This file contains a token that is unique to your project.
|
||||
# Check it into your repository along with the rest of this directory.
|
||||
# It can be used for purposes such as:
|
||||
# - ensuring you don't accidentally deploy one app on top of another
|
||||
# - providing package authors with aggregated statistics
|
||||
|
||||
yruldplduo4h.k19thi4lc1ct
|
||||
26
.meteor/packages
Normal file
26
.meteor/packages
Normal file
@@ -0,0 +1,26 @@
|
||||
# Meteor packages used by this project, one per line.
|
||||
# Check this file (and the other files in this directory) into your repository.
|
||||
#
|
||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
||||
# but you can also edit it by hand.
|
||||
|
||||
meteor-base@1.5.1 # Packages every Meteor app needs to have
|
||||
mobile-experience@1.1.0 # Packages for a great mobile UX
|
||||
mongo@1.13.0 # The database Meteor supports right now
|
||||
blaze-html-templates # Compile .html files into Meteor Blaze views
|
||||
jquery # Wrapper package for npm-installed jquery
|
||||
reactive-var@1.0.11 # Reactive variable for tracker
|
||||
tracker@1.2.0 # Meteor's client-side reactive programming library
|
||||
|
||||
standard-minifier-css@1.7.4 # CSS minifier run for production mode
|
||||
standard-minifier-js@2.7.2 # JS minifier run for production mode
|
||||
es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
|
||||
ecmascript@0.16.0 # Enable ECMAScript2015+ syntax in app code
|
||||
typescript@4.4.0 # Enable TypeScript syntax in .ts and .tsx modules
|
||||
shell-server@0.5.0 # Server-side component of the `meteor shell` command
|
||||
|
||||
|
||||
hot-module-replacement@0.4.0 # Update code in development without reloading the page
|
||||
blaze-hot # Update files using Blaze's API with HMR
|
||||
reactive-dict
|
||||
accounts-password
|
||||
3
.meteor/platforms
Normal file
3
.meteor/platforms
Normal file
@@ -0,0 +1,3 @@
|
||||
android
|
||||
browser
|
||||
server
|
||||
1
.meteor/release
Normal file
1
.meteor/release
Normal file
@@ -0,0 +1 @@
|
||||
METEOR@2.5.1
|
||||
89
.meteor/versions
Normal file
89
.meteor/versions
Normal file
@@ -0,0 +1,89 @@
|
||||
accounts-base@2.2.0
|
||||
accounts-password@2.2.0
|
||||
allow-deny@1.1.0
|
||||
autoupdate@1.8.0
|
||||
babel-compiler@7.7.0
|
||||
babel-runtime@1.5.0
|
||||
base64@1.0.12
|
||||
binary-heap@1.0.11
|
||||
blaze@2.5.0
|
||||
blaze-hot@1.1.0
|
||||
blaze-html-templates@1.2.1
|
||||
blaze-tools@1.1.2
|
||||
boilerplate-generator@1.7.1
|
||||
caching-compiler@1.2.2
|
||||
caching-html-compiler@1.2.0
|
||||
callback-hook@1.4.0
|
||||
check@1.3.1
|
||||
ddp@1.4.0
|
||||
ddp-client@2.5.0
|
||||
ddp-common@1.4.0
|
||||
ddp-rate-limiter@1.1.0
|
||||
ddp-server@2.5.0
|
||||
diff-sequence@1.1.1
|
||||
dynamic-import@0.7.2
|
||||
ecmascript@0.16.0
|
||||
ecmascript-runtime@0.8.0
|
||||
ecmascript-runtime-client@0.12.1
|
||||
ecmascript-runtime-server@0.11.0
|
||||
ejson@1.1.1
|
||||
email@2.2.0
|
||||
es5-shim@4.8.0
|
||||
fetch@0.1.1
|
||||
geojson-utils@1.0.10
|
||||
hot-code-push@1.0.4
|
||||
hot-module-replacement@0.4.0
|
||||
html-tools@1.1.2
|
||||
htmljs@1.1.1
|
||||
id-map@1.1.1
|
||||
inter-process-messaging@0.1.1
|
||||
jquery@3.0.0
|
||||
launch-screen@1.3.0
|
||||
localstorage@1.2.0
|
||||
logging@1.3.1
|
||||
meteor@1.10.0
|
||||
meteor-base@1.5.1
|
||||
minifier-css@1.6.0
|
||||
minifier-js@2.7.2
|
||||
minimongo@1.7.0
|
||||
mobile-experience@1.1.0
|
||||
mobile-status-bar@1.1.0
|
||||
modern-browsers@0.1.7
|
||||
modules@0.17.0
|
||||
modules-runtime@0.12.0
|
||||
modules-runtime-hot@0.14.0
|
||||
mongo@1.13.0
|
||||
mongo-decimal@0.1.2
|
||||
mongo-dev-server@1.1.0
|
||||
mongo-id@1.0.8
|
||||
npm-mongo@3.9.1
|
||||
observe-sequence@1.0.19
|
||||
ordered-dict@1.1.0
|
||||
promise@0.12.0
|
||||
random@1.2.0
|
||||
rate-limit@1.0.9
|
||||
react-fast-refresh@0.2.0
|
||||
reactive-dict@1.3.0
|
||||
reactive-var@1.0.11
|
||||
reload@1.3.1
|
||||
retry@1.1.0
|
||||
routepolicy@1.1.1
|
||||
service-configuration@1.3.0
|
||||
sha@1.0.9
|
||||
shell-server@0.5.0
|
||||
socket-stream-client@0.4.0
|
||||
spacebars@1.2.0
|
||||
spacebars-compiler@1.2.1
|
||||
standard-minifier-css@1.7.4
|
||||
standard-minifier-js@2.7.2
|
||||
templating@1.4.1
|
||||
templating-compiler@1.4.1
|
||||
templating-runtime@1.5.0
|
||||
templating-tools@1.2.0
|
||||
tracker@1.2.0
|
||||
typescript@4.4.0
|
||||
ui@1.0.13
|
||||
underscore@1.0.10
|
||||
url@1.3.2
|
||||
webapp@1.13.0
|
||||
webapp-hashing@1.1.0
|
||||
194
client/main.css
Normal file
194
client/main.css
Normal file
@@ -0,0 +1,194 @@
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background-color: #315481;
|
||||
background-image: linear-gradient(to bottom, #315481, #918e82 100%);
|
||||
background-attachment: fixed;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
button {
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
border: none;
|
||||
color: white;
|
||||
box-shadow: 0 3px 3px rgba(34, 25, 25, 0.4);
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.app-header {
|
||||
flex-grow: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.main::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
header {
|
||||
background: #d2edf4;
|
||||
background-image: linear-gradient(to bottom, #d0edf5, #e1e5f0 100%);
|
||||
padding: 20px 15px 15px 15px;
|
||||
position: relative;
|
||||
box-shadow: 0 3px 3px rgba(34, 25, 25, 0.4);
|
||||
}
|
||||
|
||||
.app-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.app-bar h1 {
|
||||
font-size: 1.5em;
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.task-form {
|
||||
display: flex;
|
||||
margin: 16px;
|
||||
}
|
||||
|
||||
.task-form > input {
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
padding: 10px 6px;
|
||||
background: transparent;
|
||||
border: 1px solid #aaa;
|
||||
width: 100%;
|
||||
font-size: 1em;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.task-form > input:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.task-form > button {
|
||||
min-width: 100px;
|
||||
height: 95%;
|
||||
background-color: #315481;
|
||||
}
|
||||
|
||||
.tasks {
|
||||
list-style-type: none;
|
||||
padding-inline-start: 0;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
margin-block-start: 0;
|
||||
margin-block-end: 0;
|
||||
}
|
||||
|
||||
.tasks > li {
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
border-bottom: #eee solid 1px;
|
||||
}
|
||||
|
||||
.tasks > li > span {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.tasks > li > button {
|
||||
justify-self: flex-end;
|
||||
background-color: #ff3046;
|
||||
}
|
||||
|
||||
.filter {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.filter > button {
|
||||
background-color: #62807e;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.login-form > div {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.login-form > div > label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.login-form > div > input {
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
padding: 10px 6px;
|
||||
background: transparent;
|
||||
border: 1px solid #aaa;
|
||||
width: 100%;
|
||||
font-size: 1em;
|
||||
margin-right: 16px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.login-form > div > input:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.login-form > div > button {
|
||||
background-color: #62807e;
|
||||
}
|
||||
|
||||
.user {
|
||||
display: flex;
|
||||
|
||||
align-self: flex-end;
|
||||
|
||||
margin: 8px 16px 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-weight: bold;
|
||||
}
|
||||
11
client/main.html
Normal file
11
client/main.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge"/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, height=device-height, viewport-fit=cover, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
|
||||
/>
|
||||
<meta name="mobile-web-app-capable" content="yes"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||
<title>Simple todo</title>
|
||||
</head>
|
||||
1
client/main.js
Normal file
1
client/main.js
Normal file
@@ -0,0 +1 @@
|
||||
import '../imports/ui/App.js';
|
||||
56
imports/api/tasksMethods.js
Normal file
56
imports/api/tasksMethods.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import { TasksCollection } from '../db/TasksCollection';
|
||||
|
||||
Meteor.methods({
|
||||
'tasks.insert'(text) {
|
||||
check(text, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('Not authorized.');
|
||||
}
|
||||
|
||||
TasksCollection.insert({
|
||||
text,
|
||||
createdAt: new Date,
|
||||
userId: this.userId,
|
||||
})
|
||||
},
|
||||
|
||||
'tasks.remove'(taskId) {
|
||||
check(taskId, String);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('Not authorized.');
|
||||
}
|
||||
|
||||
const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
|
||||
|
||||
if (!task) {
|
||||
throw new Meteor.Error('Access denied.');
|
||||
}
|
||||
|
||||
TasksCollection.remove(taskId);
|
||||
},
|
||||
|
||||
'tasks.setIsChecked'(taskId, isChecked) {
|
||||
check(taskId, String);
|
||||
check(isChecked, Boolean);
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error('Not authorized.');
|
||||
}
|
||||
|
||||
const task = TasksCollection.findOne({ _id: taskId, userId: this.userId });
|
||||
|
||||
if (!task) {
|
||||
throw new Meteor.Error('Access denied.');
|
||||
}
|
||||
|
||||
TasksCollection.update(taskId, {
|
||||
$set: {
|
||||
isChecked,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
6
imports/api/tasksPublications.js
Normal file
6
imports/api/tasksPublications.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { TasksCollection } from '/imports/db/TasksCollection';
|
||||
|
||||
Meteor.publish('tasks', function publishTasks() {
|
||||
return TasksCollection.find({ userId: this.userId });
|
||||
});
|
||||
3
imports/db/TasksCollection.js
Normal file
3
imports/db/TasksCollection.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import { Mongo } from 'meteor/mongo';
|
||||
|
||||
export const TasksCollection = new Mongo.Collection('tasks');
|
||||
54
imports/ui/App.html
Normal file
54
imports/ui/App.html
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
<body>
|
||||
{{> mainContainer }}
|
||||
</body>
|
||||
|
||||
<template name="mainContainer">
|
||||
<div class="app">
|
||||
<header>
|
||||
<div class="app-bar">
|
||||
<div class="app-header">
|
||||
<h1>📝️ To Do List {{incompleteCount}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main">
|
||||
{{#if isUserLogged}}
|
||||
<div class="user">
|
||||
{{getUser.username}} 🚪
|
||||
</div>
|
||||
{{> form }}
|
||||
|
||||
<div class="filter">
|
||||
<button id="hide-completed-button">
|
||||
{{#if hideCompleted}}
|
||||
Show All
|
||||
{{else}}
|
||||
Hide Completed
|
||||
{{/if}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{#if isLoading}}
|
||||
<div class="loading">loading...</div>
|
||||
{{/if}}
|
||||
|
||||
<ul class="tasks">
|
||||
{{#each tasks}}
|
||||
{{> task}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{else}}
|
||||
{{> login }}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="form">
|
||||
<form class="task-form">
|
||||
<input type="text" name="text" placeholder="Type to add new tasks" />
|
||||
<button type="submit">Add Task</button>
|
||||
</form>
|
||||
</template>
|
||||
103
imports/ui/App.js
Normal file
103
imports/ui/App.js
Normal file
@@ -0,0 +1,103 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { TasksCollection } from "../db/TasksCollection";
|
||||
import { ReactiveDict } from 'meteor/reactive-dict';
|
||||
import './App.html';
|
||||
import './Task.js';
|
||||
import "./Login.js";
|
||||
|
||||
const HIDE_COMPLETED_STRING = "hideCompleted";
|
||||
const getUser = () => Meteor.user();
|
||||
const isUserLogged = () => !!getUser();
|
||||
const IS_LOADING_STRING = "isLoading";
|
||||
const getTasksFilter = () => {
|
||||
const user = getUser();
|
||||
|
||||
const hideCompletedFilter = { isChecked: { $ne: true } };
|
||||
|
||||
const userFilter = user ? { userId: user._id } : {};
|
||||
|
||||
const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter };
|
||||
|
||||
return { userFilter, pendingOnlyFilter };
|
||||
}
|
||||
|
||||
Template.mainContainer.events({
|
||||
"click #hide-completed-button"(event, instance) {
|
||||
const currentHideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
|
||||
instance.state.set(HIDE_COMPLETED_STRING, !currentHideCompleted);
|
||||
},
|
||||
'click .user'() {
|
||||
Meteor.logout();
|
||||
}
|
||||
});
|
||||
|
||||
Template.mainContainer.onCreated(function mainContainerOnCreated() {
|
||||
this.state = new ReactiveDict();
|
||||
});
|
||||
|
||||
Template.mainContainer.onCreated(function mainContainerOnCreated() {
|
||||
this.state = new ReactiveDict();
|
||||
|
||||
const handler = Meteor.subscribe('tasks');
|
||||
Tracker.autorun(() => {
|
||||
this.state.set(IS_LOADING_STRING, !handler.ready());
|
||||
});
|
||||
});
|
||||
|
||||
Template.mainContainer.helpers({
|
||||
tasks() {
|
||||
const instance = Template.instance();
|
||||
const hideCompleted = instance.state.get(HIDE_COMPLETED_STRING);
|
||||
|
||||
const { pendingOnlyFilter, userFilter } = getTasksFilter();
|
||||
|
||||
if (!isUserLogged()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return TasksCollection.find(hideCompleted ? pendingOnlyFilter : userFilter, {
|
||||
sort: { createdAt: -1 },
|
||||
}).fetch();
|
||||
},
|
||||
isLoading() {
|
||||
const instance = Template.instance();
|
||||
return instance.state.get(IS_LOADING_STRING);
|
||||
},
|
||||
hideCompleted() {
|
||||
return Template.instance().state.get(HIDE_COMPLETED_STRING);
|
||||
},
|
||||
incompleteCount() {
|
||||
if (!isUserLogged()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const { pendingOnlyFilter } = getTasksFilter();
|
||||
|
||||
const incompleteTasksCount = TasksCollection.find(pendingOnlyFilter).count();
|
||||
return incompleteTasksCount ? `(${incompleteTasksCount})` : '';
|
||||
},
|
||||
isUserLogged() {
|
||||
return isUserLogged();
|
||||
},
|
||||
getUser() {
|
||||
return getUser();
|
||||
}
|
||||
});
|
||||
|
||||
Template.form.events({
|
||||
"submit .task-form"(event) {
|
||||
// Prevent default browser form submit
|
||||
event.preventDefault();
|
||||
|
||||
// Get value from form element
|
||||
const target = event.target;
|
||||
const text = target.text.value;
|
||||
|
||||
// Insert a task into the collection
|
||||
Meteor.call('tasks.insert', text);
|
||||
|
||||
// Clear form
|
||||
target.text.value = '';
|
||||
}
|
||||
})
|
||||
|
||||
28
imports/ui/Login.html
Normal file
28
imports/ui/Login.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<template name="login">
|
||||
<form class="login-form">
|
||||
<div>
|
||||
<label htmlFor="username">Username</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
name="username"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="password">Password</label>
|
||||
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
name="password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit">Log In</button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
16
imports/ui/Login.js
Normal file
16
imports/ui/Login.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Template } from 'meteor/templating';
|
||||
import './Login.html';
|
||||
|
||||
Template.login.events({
|
||||
'submit .login-form'(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const target = e.target;
|
||||
|
||||
const username = target.username.value;
|
||||
const password = target.password.value;
|
||||
|
||||
Meteor.loginWithPassword(username, password);
|
||||
}
|
||||
});
|
||||
7
imports/ui/Task.html
Normal file
7
imports/ui/Task.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<template name="task">
|
||||
<li>
|
||||
<input type="checkbox" checked="{{isChecked}}" class="toggle-checked" />
|
||||
<span>{{text}}</span>
|
||||
<button class="delete">×</button>
|
||||
</li>
|
||||
</template>
|
||||
15
imports/ui/Task.js
Normal file
15
imports/ui/Task.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
|
||||
import './Task.html';
|
||||
|
||||
|
||||
Template.task.events({
|
||||
'click .toggle-checked'() {
|
||||
Meteor.call('tasks.setIsChecked', this._id, !this.isChecked);
|
||||
},
|
||||
'click .delete'() {
|
||||
Meteor.call('tasks.remove', this._id);
|
||||
},
|
||||
});
|
||||
|
||||
1216
package-lock.json
generated
Normal file
1216
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
package.json
Normal file
23
package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "simple-todos-blaze",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "meteor run",
|
||||
"test": "meteor test --once --driver-package meteortesting:mocha",
|
||||
"test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
|
||||
"visualize": "meteor --production --extra-packages bundle-visualizer"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.15.4",
|
||||
"bcrypt": "^5.0.1",
|
||||
"jquery": "^3.6.0",
|
||||
"meteor-node-stubs": "^1.1.0"
|
||||
},
|
||||
"meteor": {
|
||||
"mainModule": {
|
||||
"client": "client/main.js",
|
||||
"server": "server/main.js"
|
||||
},
|
||||
"testModule": "tests/main.js"
|
||||
}
|
||||
}
|
||||
38
server/main.js
Normal file
38
server/main.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Accounts } from 'meteor/accounts-base';
|
||||
import { TasksCollection } from '/imports/db/TasksCollection';
|
||||
import '/imports/api/tasksMethods';
|
||||
import '/imports/api/tasksPublications';
|
||||
|
||||
const insertTask = (taskText, user) =>
|
||||
TasksCollection.insert({
|
||||
text: taskText,
|
||||
userId: user._id,
|
||||
createdAt: new Date(),
|
||||
});
|
||||
|
||||
const SEED_USERNAME = 'meteorite';
|
||||
const SEED_PASSWORD = 'password';
|
||||
|
||||
Meteor.startup(() => {
|
||||
if (!Accounts.findUserByUsername(SEED_USERNAME)) {
|
||||
Accounts.createUser({
|
||||
username: SEED_USERNAME,
|
||||
password: SEED_PASSWORD,
|
||||
});
|
||||
}
|
||||
|
||||
const user = Accounts.findUserByUsername(SEED_USERNAME);
|
||||
|
||||
if (TasksCollection.find().count() === 0) {
|
||||
[
|
||||
'First Task',
|
||||
'Second Task',
|
||||
'Third Task',
|
||||
'Fourth Task',
|
||||
'Fifth Task',
|
||||
'Sixth Task',
|
||||
'Seventh Task',
|
||||
].forEach(taskText => insertTask(taskText, user));
|
||||
}
|
||||
});
|
||||
20
tests/main.js
Normal file
20
tests/main.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import assert from "assert";
|
||||
|
||||
describe("simple-todos-blaze", function () {
|
||||
it("package.json has correct name", async function () {
|
||||
const { name } = await import("../package.json");
|
||||
assert.strictEqual(name, "simple-todos-blaze");
|
||||
});
|
||||
|
||||
if (Meteor.isClient) {
|
||||
it("client is not server", function () {
|
||||
assert.strictEqual(Meteor.isServer, false);
|
||||
});
|
||||
}
|
||||
|
||||
if (Meteor.isServer) {
|
||||
it("server is not client", function () {
|
||||
assert.strictEqual(Meteor.isClient, false);
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user