I've been following along with the tutorial, and i had been having some issues, but i was able to solve all of them on my own - but now I've come to this point. i ran the "meteor remove insecure" and i was pretty sure i updated my tasks.js correctly to reflect my meteor methods. i changed the import on my main.js and TaskForm.jsx and App.jsx
EDIT ** The error i am receiving does not show up in vsCode, the error only shows in the console. but, interestingly, if you look at my methods, you see the warning message is supposed to say "Not Authorized", however the warning that appears in the console says "Update failed: Access denied"
MOST of my variables are named exactly the same as in the tutorial, some are not... and that is probably adding a layer of confusion on top of the learning process... for example i have Task, Tasks, tasksList, and taskList, are all different variables... i am aware i should make those more legible, just trying to make it "work" for now.
tasks.js:
import { Mongo } from 'meteor/mongo';
import { check } from 'meteor/check';
export const Tasks = new Mongo.Collection('taskList');
Meteor.methods({
'taskList.insert'(text) {
check(text, String);
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
Tasks.insert({
text,
createdAt: new Date,
owner: this.userId,
username: Meteor.users.findOne(this.userId).username
})
},
'taskList.remove'(taskId) {
check(taskId, String);
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
Tasks.remove(taskId);
},
'taskList.setChecked'(taskId, isChecked) {
check(taskId, String);
check(isChecked, Boolean);
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
Tasks.update(taskId, {
$set: {
isChecked
}
});
}
});
App.jsx:
import React, { useState } from 'react';
import { useTracker } from 'meteor/react-meteor-data';
import _ from 'lodash';
import { Task } from './Task';
import { Tasks } from '/imports/api/tasks';
import { TaskForm } from './TaskForm';
import { LoginForm } from './LoginForm';
const toggleChecked = ({ _id, isChecked }) => {
Tasks.update(_id, {
$set: {
isChecked: !isChecked
}
})
};
const deleteTask = ({ _id }) => Tasks.remove(_id);
const logoutFunction = (e) => {
Meteor.logout(e)
}
export const App = () => {
const filter = {};
const [hideCompleted, setHideCompleted] = useState(false);
if (hideCompleted) {
_.set(filter, 'isChecked', false);
}
const { tasksList, incompleteTasksCount, user } = useTracker(() => ({
tasksList: Tasks.find(filter, { sort: { createdAt: -1 } }).fetch(),
incompleteTasksCount: Tasks.find({ isChecked: { $ne: true }}).count(),
user: Meteor.user(),
}));
if (!user) {
return (
<div className="simple-todos-react">
<LoginForm/>
</div>
);
}
return (
<div className="simple-todos-react">
<button onClick ={logoutFunction}>Log Out</button>
<h1>Flight List ({ incompleteTasksCount })</h1>
<div className="filters">
<label>
<input
type="checkbox"
readOnly
checked={ Boolean(hideCompleted) }
onClick={() => setHideCompleted(!hideCompleted)}
/>
Hide Completed
</label>
</div>
<ul className="tasks">
{ tasksList.map(task1 => <Task
key={ task1._id }
task={ task1 }
onCheckboxClick={toggleChecked}
onDeleteClick={deleteTask}/>) }
</ul>
<TaskForm user={user}/>
</div>
);
};
TaskForm.jsx:
import React, { useState } from 'react';
import { Tasks } from '/imports/api/tasks';
export const TaskForm = ({ user }) => {
const [text, setText] = useState("");
const handleSubmit = () => {
if (!text) return;
Tasks.insert({
text: text.trim(),
createdAt: new Date(),
isChecked: false,
owner: user._id,
});
setText("");
};
return (
<form className="task-form" onSubmit={handleSubmit}>
<input
type="text"
placeholder="Type to add new tasks"
value={text}
onChange={(e) => setText(e.target.value)}
/>
<button type="submit">Add Task</button>
</form>
);
};
main.js:
import { Meteor } from 'meteor/meteor';
import { Tasks } from '/imports/api/tasks';
function insertTask({ text }) {
Tasks.insert({text});
}
Meteor.startup(() => {
if (!Accounts.findUserByUsername('meteorite')) {
Accounts.createUser({
username: 'meteorite',
password: 'password'
});
}
if (Tasks.find().count() === 0) { //this is for basic data that will never render once app is live.
[
{text:'updated THE Firstttt Task again this wont show'},
{text:'the Second Task'},
{text:'update 1 Third Task'},
{text:'Fourth Task'},
{text:'Fifth Task'},
{text:'Sixth Task'},
{text:'Seventh Task'}
].forEach(eachTask=>{insertTask(eachTask)})
}
});
Task.jsx:
import React from 'react';
import classnames from 'classnames';
export const Task = ({ task, onCheckboxClick, onDeleteClick }) => {
const classes = classnames('task', {
'checked': Boolean(task.isChecked)
});
return (
<li className={classes}>
<button onClick={ () => onDeleteClick(task) }>×</button>
<span>{ task.text }</span>
<input
type="checkbox"
checked={ Boolean(task.isChecked) }
onClick={ () => onCheckboxClick(task) }
readOnly
/>
</li>
);
};