ログインしたユーザーがTODOリストを作成できるようにする
ユーザーごとに異なるクッキーを作成し、ユーザーIDを用いて各ユーザーの情報を分離して管理する。
TODOリスト情報
- タスク名
- タスク説明
- タスク期限
- ユーザー情報
ログイン機能について
使用技術
- html,
- css
- javascript
認証方法
- パスワード
- ユーザーID
保存情報
- パスワード
- ユーザーID
- ユーザー名
- ユーザーアイコン
その他
- APIなし
- フロントエンドのみ
- 保存する箇所はCookiesに保存する
ファイル構成
login |--html
| |
| |--login.html
| |--profile.html
| |--create-account.html
| |--todo.html
|
|--app.js
|
|--styles.css
login.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ログイン</title>
<link rel="stylesheet" href="styles.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css">
</head>
<body>
<div class="container">
<h2>ログイン</h2>
<form id="loginForm">
<input type="email" id="email" placeholder="メールアドレス" required>
<input type="password" id="password" placeholder="パスワード" required>
<input type="text" id="userId" placeholder="ユーザーID" required> <!-- ユーザーID入力フィールドを追加 -->
<button type="submit">ログイン</button>
</form>
<p>アカウントをお持ちでない方は <a href="create-account.html">新規アカウント作成</a></p>
</div>
<script src="app.js"></script>
</body>
</html>
profile.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ユーザープロフィール</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h2>ようこそ、<span id="displayName"></span>さん</h2>
<img id="displayIcon" src="" alt="User Icon">
<!-- TODOリストへのリンク追加 -->
<p><a href="todo.html" class="todo-link">TODOリストを管理</a></p>
</div>
<div id="displayName"></div>
<script src="app.js"></script>
</body>
</html>
create-account.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>新規アカウント作成</title>
<link rel="stylesheet" href="styles.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css">
</head>
<body>
<div class="container">
<h2>新規アカウント作成</h2>
<form id="accountForm">
<input type="email" id="newEmail" placeholder="メールアドレス" required>
<input type="password" id="newPassword" placeholder="パスワード" required>
<input type="text" id="username" placeholder="ユーザー名" required>
<input type="text" id="newUserId" placeholder="ユーザーID" required> <!-- ユーザーID入力フィールドを追加 -->
<input type="file" id="userIcon" accept="image/*">
<button type="submit">アカウント作成</button>
</form>
</div>
<script src="app.js"></script>
</body>
</html>
todo.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TODOリスト</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h2>TODOリスト</h2>
<form id="todoForm">
<input type="text" id="taskName" placeholder="タスク名" required>
<textarea id="taskDescription" placeholder="タスク説明" required></textarea>
<input type="date" id="taskDeadline" required>
<button type="submit">タスク追加</button>
</form>
<!-- プロフィールへ戻るボタン追加 -->
<button onclick="window.location.href='profile.html'" class="back-button">プロフィールに戻る</button>
<div id="todoList">
<!-- JavaScriptで動的にタスクを表示 -->
</div>
<div id="todoList" class="todo-list"></div>
</div>
<script src="app.js"></script>
</body>
</html>
app.js
// ログインフォームの処理
if (document.getElementById('loginForm')) { //HTMLの'loginForm'を確認
document.getElementById('loginForm').addEventListener('submit', function(e) { //'loginForm'があった場合のイベントを追加
e.preventDefault(); //デフォルトの動作をキャンセルする
const email = document.getElementById('email').value; //ユーザーが入力したemailを取得
const password = document.getElementById('password').value; //ユーザーが入力したpasswordを取得
const userId = document.getElementById('userId').value; // ユーザーが入力したユーザーIDを取得
const storedEmail = getCookie('email', userId);
const storedPassword = getCookie('password', userId);
if (email === storedEmail && password === storedPassword) {
window.location.href = 'profile.html';
} else {
toastr.error('メールアドレスまたはパスワードが正しくありません。');
}
});
}
// アカウント作成フォームの処理
if (document.getElementById('accountForm')) //HTMLの'accountForm'を確認
document.getElementById('accountForm').addEventListener('submit', async function(e) { //'accountFormがあった場合のイベントを追加 //asyncを追加
e.preventDefault(); //デフォルトの動作をキャンセルする
const email = document.getElementById('newEmail').value; //ユーザーが入力したemailを取得
const password = document.getElementById('newPassword').value; //ユーザーが入力したpasswordを取得
const username = document.getElementById('username').value; //ユーザーが入力したユーザー名を取得
const userId = document.getElementById('newUserId').value; // ユーザーが入力したユーザーIDを取得
const userIcon = document.getElementById('userIcon').files[0]; //ユーザーが入力したアイコンを取得
const formData = new FormData(); //空のフォーム
formData.append('image', userIcon); //サーバにユーザが指定したアイコンデータを送信する
try {
const response = await fetch(`https://api.imgbb.com/1/upload?key=c0f0b6237007dc47943f085d13b621c1`, { //アップロード先のURL
method: 'POST',
body: formData //送信するデータ
});
const data = await response.json();
if (data.status === 200) {
const imageUrl = data.data.url;
setCookie('userId', userId, 7);
setCookie('email', email, 7, userId);
setCookie('password', password, 7, userId);
setCookie('username', username, 7, userId);
setCookie('userIcon', imageUrl, 7, userId);
toastr.success('アカウントが正常に作成されました。');
window.location.href = 'login.html';
} else {
throw new Error('Failed to upload image');
}
} catch (error) {
console.error('Error uploading image:', error);
toastr.error('画像のアップロードに失敗しました。');
}
}
// プロファイルページでユーザー情報を表示
if (window.location.pathname.includes('profile.html')) {
// ログイン時
const userId = getCookie('userId'); // ユーザーIDを取得
// プロファイル表示時
const username = getCookie('username', userId);
const userIcon = getCookie('userIcon', userId);
if (username && userIcon) { //ユーザー名とアイコンが存在するか確認
document.getElementById('displayName').textContent = username; //クッキーから取得したユーザー名を表示
document.getElementById('displayIcon').src = userIcon; //クッキーから取得したアイコンを表示
} else {
window.location.href = 'login.html'; //クッキーに情報がない場合'login.html'ページに移動
}
}
// Cookieを設定する関数
function setCookie(name, value, days, userId) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
const expires = "expires=" + date.toUTCString();
document.cookie = userId + "_" + name + "=" + value + ";" + expires + ";path=/";
}
// Cookieを取得する関数
function getCookie(name, userId) {
const nameEQ = userId + "_" + name + "=";
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') c = c.substring(1);
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
// TODOリストページの処理
if (window.location.pathname.includes('todo.html')) {
document.getElementById('todoForm').addEventListener('submit', function(e) {
console.log(`追加ボタンを押したら発火`)
e.preventDefault(); //デフォルトの動作をキャンセルする
const taskName = document.getElementById('taskName').value; //ユーザーが入力したタスク名を取得
console.log(`taskName`, taskName)
const taskDescription = document.getElementById('taskDescription').value; //ユーザーが入力したタスクの説明文を取得
console.log(`taskDescription`, taskDescription)
const taskDeadline = document.getElementById('taskDeadline').value; //ユーザーが入力した期限を取得
console.log(`taskDeadline`, taskDeadline)
const newTask = { //新しいタスクの作成と追加
name: taskName, //ユーザーが入力したタスク名を保持
description: taskDescription, //ユーザーが入力したタスクの説明を保持
deadline: taskDeadline //ユーザーが入力したタスクの期限を保持
};
console.log(`newTask`, newTask)
addTask(newTask); //ユーザーがクリックすると新しいタスクを追加できる
displayTasks(); //更新されたタスクリストをユーザーに表示
});
function addTask(task) {
console.log(`addTask()`)
const tasks = getTasks(); //保存されているタスクのリストを返す
console.log(`tasks`, tasks)
tasks.push(task); //新しいタスクを追加
console.log(`tasks`, tasks)
saveTasks(tasks); //変更されたタスクを保存
}
function displayTasks() {
console.log(`displayTasks`)
const tasks = getTasks(); //保存されている全てのタスクを取得
console.log(`tasks`, tasks)
const todoList = document.getElementById('todoList'); //HTMLの'todoList'を取得
console.log(`todoList`, todoList)
todoList.innerHTML = ''; // 'todoList'を空に設定して新たにタスクを表示する準備
tasks.forEach((task, index) => { //タスクに対して処理を行うループ
console.log(`task`, task)
console.log(`index`, index)
const taskElement = document.createElement('div'); //各タスクの情報を囲むコンテナ
console.log(`taskElement`, taskElement)
taskElement.innerHTML = `
<p>タスク名: ${task.name}</p>
<p>説明: ${task.description}</p>
<p>期限: ${task.deadline}</p>
<button onclick="deleteTask(${index})">削除</button>
`; //タスクの詳細(名前、説明、期限)と削除ボタンを含むHTMLを設定
console.log(`taskElement`, taskElement)
todoList.appendChild(taskElement); //画面上にタスクが表示される
console.log(`todoList`, todoList)
});
}
function deleteTask(index) {
console.log(`deleteTask()`)
const tasks = getTasks(); //保存されているタスクを取得
console.log(`tasks`, tasks)
tasks.splice(index, 1); //1つのタスクを削除
console.log(`tasks`, tasks)
saveTasks(tasks); //更新されたタスクリストを再び保存
displayTasks(); //
}
function getTasks() {
const userId = getCookie('userId');
const tasks = getCookie('tasks', userId);
return tasks ? JSON.parse(tasks) : [];
}
function saveTasks(tasks) {
const userId = getCookie('userId');
setCookie('tasks', JSON.stringify(tasks), 7, userId);
}
}
// 既存の Cookie 操作関数 `setCookie` と `getCookie` はそのまま利用
// ページロード時にタスクを表示
window.onload = function() {
if (window.location.pathname.includes('todo.html')) {
displayTasks();
}
};
styles.css
/* 基本設定 */
body {
font-family: 'Poppins', sans-serif;
background-color: #f5f5f5;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
/* コンテナのスタイル */
.container {
width: 100%;
max-width: 350px;
padding: 30px;
background-color: white;
border-radius: 10px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
text-align: center;
}
/* 見出しスタイル */
h2 {
margin-bottom: 20px;
font-size: 1.5rem;
color: #333;
font-weight: 600;
}
/* 入力フィールドのスタイル */
input[type="email"],
input[type="password"],
input[type="text"],
input[type="file"] {
width: 80%;
max-width: 280px;
padding: 12px 15px;
margin: 10px 0;
border: 2px solid #ddd;
border-radius: 8px;
background-color: #f9f9f9;
font-size: 1rem;
transition: border 0.3s, background-color 0.3s;
}
/* フォーカス時のスタイル */
input[type="email"]:focus,
input[type="password"]:focus,
input[type="text"]:focus {
border-color: #b654c5;
background-color: white;
outline: none;
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
}
/* ボタンのスタイル */
button {
width: 80%;
max-width: 280px;
padding: 12px;
background-color: #b654c5;
color: white;
font-size: 1rem;
font-weight: 600;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s, box-shadow 0.3s;
}
/* ボタンホバー時のエフェクト */
button:hover {
background-color: #b654c5;
box-shadow: 0 4px 12px rgba(0, 91, 179, 0.2);
}
/* リンクのスタイル */
p a {
color: #b654c5;
text-decoration: none;
font-weight: 600;
transition: color 0.3s ease;
}
p a:hover {
color: #b654c5;
}
/* ユーザーアイコンのスタイル */
#displayIcon {
width: 100px;
height: 100px;
border-radius: 50%;
object-fit: cover;
margin-top: 10px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
/* レスポンシブ設定 */
@media (max-width: 768px) {
.container {
width: 90%;
}
}
/* TODOリストのスタイル調整 */
.todo-list {
width: 100%;
max-width: 350px;
margin-top: 20px;
padding: 10px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.todo-list div {
padding: 10px;
margin: 5px 0;
border-bottom: 1px solid #eee;
}
.todo-list div:last-child {
border-bottom: none;
}
.todo-list p {
margin: 5px 0;
color: #333;
}
button {
margin-top: 10px;
}