firebase 掲示板テスト

ここまでのものは

掲示板




掲示板







<!-- Firebase SDK -->
<script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-storage-compat.js"></script>

<div>
  <h3>掲示板</h3>
  <p id="postCount"></p>
  <input type="text" id="nameInput" placeholder="名前 (15文字以内)" maxlength="15" required><br>
  <input type="email" id="emailInput" placeholder="メールアドレス (任意)"><br>
  <input type="file" id="iconInput" accept="image/*"><br>
  <div id="stampGallery"></div>
  <textarea id="commentInput" placeholder="コメントを入力してください" rows="3" cols="40" required></textarea><br>
  <button id="submitBtn">投稿</button>
  <select id="sortSelect">
    <option value="created">新着順</option>
    <option value="likes">いいね順</option>
  </select>
  <div id="toast" style="display:none; position:fixed; bottom:10px; right:10px; background:#333; color:#fff; padding:10px; border-radius:5px;">投稿しました</div>
  <div id="commentList"></div>
</div>

<script>
const firebaseConfig = {
  apiKey: "AIzaSyBXk0dW2k1W5w32f1f12viaV5s-j6iM1k",
  authDomain: "keiko-salon-board.firebaseapp.com",
  projectId: "keiko-salon-board",
  storageBucket: "keiko-salon-board.appspot.com",
  messagingSenderId: "462083553388",
  appId: "1:462083553388:web:07d442b8d80ce9a3f53d219"
};

firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
const storage = firebase.storage();
let selectedStamp = "";

window.addEventListener("DOMContentLoaded", async () => {
  document.getElementById("submitBtn").addEventListener("click", postComment);
  document.getElementById("sortSelect").addEventListener("change", loadComments);
  loadComments();
  await loadStampGallery();
});

function showToast(msg) {
  const toast = document.getElementById("toast");
  toast.textContent = msg;
  toast.style.display = "block";
  setTimeout(() => toast.style.display = "none", 3000);
}

async function loadStampGallery() {
  const stampRef = storage.ref("stamps");
  const result = await stampRef.listAll();
  const gallery = document.getElementById("stampGallery");
  gallery.innerHTML = "<p>スタンプを選んでください:</p>";
  result.items.forEach(async (itemRef) => {
    const url = await itemRef.getDownloadURL();
    const img = document.createElement("img");
    img.src = url;
    img.width = 40;
    img.style.margin = "5px";
    img.style.cursor = "pointer";
    img.onclick = () => {
      selectedStamp = url;
      document.querySelectorAll('#stampGallery img').forEach(i => i.style.border = 'none');
      img.style.border = '2px solid red';
    };
    gallery.appendChild(img);
  });
}

async function postComment() {
  const name = document.getElementById("nameInput").value.trim().substring(0, 15);
  const email = document.getElementById("emailInput").value.trim();
  const text = document.getElementById("commentInput").value.trim();
  const file = document.getElementById("iconInput").files[0];
  const stamp = selectedStamp;

  if (!name || !text) return showToast("名前とコメントは必須です");

  let iconURL = "";
  try {
    if (file) {
      const storageRef = storage.ref("icons/" + Date.now() + "_" + file.name);
      await storageRef.put(file);
      iconURL = await storageRef.getDownloadURL();
    }
  } catch (e) {
    console.error("🔥 画像アップロードに失敗:", e);
    showToast("画像アップロードに失敗しました");
    return;
  }

  try {
    await db.collection("comments").add({
      name,
      email,
      text,
      icon: iconURL,
      stamp: stamp,
      created: new Date(),
      likes: 0,
      parentId: null,
      reports: 0
    });

    // フォームリセット
    document.getElementById("commentInput").value = "";
    document.getElementById("iconInput").value = "";
    document.getElementById("emailInput").value = "";
    selectedStamp = "";
    showToast("投稿が完了しました");
    loadComments();
  } catch (e) {
    console.error("🔥 Firestoreへの投稿に失敗:", e);
    showToast("投稿に失敗しました");
  }
}



    await db.collection("comments").add({
      name,
      email,
      icon: iconURL,
      stamp: selectedStamp,
      text,
      created: new Date(),
      likes: 0,
      parentId: null,
      reports: 0
    });

    showToast("投稿しました");
    document.getElementById("commentInput").value = "";
    document.getElementById("iconInput").value = "";
    selectedStamp = "";
    loadComments();
  } catch (e) {
    console.error("画像付き投稿エラー:", e);
    showToast("画像投稿に失敗しました");
  }
}

async function loadComments() {
  const sort = document.getElementById("sortSelect").value;
  const snapshot = await db.collection("comments").where("parentId", "==", null).orderBy(sort, "desc").get();
  document.getElementById("postCount").innerText = `総投稿数:${snapshot.size}`;

  const html = await Promise.all(snapshot.docs.map(async doc => {
    const data = doc.data();
    const replies = await db.collection("comments").where("parentId", "==", doc.id).orderBy("created").get();

    const replyHTML = replies.docs.map(replyDoc => {
      const reply = replyDoc.data();
      return `
        <div style="margin-left: 40px;">
          <strong>${reply.name}</strong>:${reply.text}<br>
          ${reply.stamp ? `<img src="${reply.stamp}" width="30">` : ""}
          <button onclick="likeComment('${replyDoc.id}')">❤️ ${reply.likes || 0}</button>
          <button onclick="reportComment('${replyDoc.id}')">🚩</button>
        </div>`;
    }).join("");

    const iconTag = data.icon ? `<img src="${data.icon}" width="40" style="border-radius:50%; margin-right:10px;">` : "";

    return `
      <div style="border-bottom:1px solid #ccc; margin-bottom:10px;">
        <div style="display:flex; align-items:center;">
          ${iconTag}<strong>${data.name}</strong>(${new Date(data.created.toDate()).toLocaleString()})
        </div>
        <div>${data.text.replace(/\n/g, "<br>")}</div>
        ${data.stamp ? `<img src="${data.stamp}" width="30">` : ""}<br>
        <button onclick="likeComment('${doc.id}')">❤️ ${data.likes || 0}</button>
        <button onclick="showReplyBox('${doc.id}')">返信</button>
        <button onclick="reportComment('${doc.id}')">🚩</button>
        <div id="replyBox-${doc.id}" style="display:none;">
          <input type="text" placeholder="名前 (15文字以内)" id="replyName-${doc.id}" maxlength="15" required><br>
          <input type="email" placeholder="メールアドレス (任意)" id="replyEmail-${doc.id}"><br>
          <textarea rows="3" cols="40" placeholder="返信コメント" id="replyText-${doc.id}" required></textarea><br>
          <button onclick="submitReply('${doc.id}')">返信する</button>
        </div>
        ${replyHTML}
      </div>`;
  }));

  document.getElementById("commentList").innerHTML = html.join("");
}

function showReplyBox(id) {
  document.getElementById(`replyBox-${id}`).style.display = "block";
}

async function submitReply(parentId) {
  const name = document.getElementById(`replyName-${parentId}`).value.trim().substring(0, 15);
  const email = document.getElementById(`replyEmail-${parentId}`).value.trim();
  const text = document.getElementById(`replyText-${parentId}`).value.trim();
  if (!name || !text) return;

  await db.collection("comments").add({
    name,
    email,
    icon: "",
    stamp: "",
    text,
    created: new Date(),
    likes: 0,
    parentId,
    reports: 0
  });
  loadComments();
}

async function likeComment(id) {
  const key = `liked-${id}`;
  if (localStorage.getItem(key)) return;
  const ref = db.collection("comments").doc(id);
  await ref.update({ likes: firebase.firestore.FieldValue.increment(1) });
  localStorage.setItem(key, true);
  loadComments();
}

async function reportComment(id) {
  const ref = db.collection("comments").doc(id);
  await ref.update({ reports: firebase.firestore.FieldValue.increment(1) });
  showToast("通報しました");
}
</script>

すべてはアイデアから始まります⁠。ビジネスを始める場合でも⁠、趣味をただの楽しみ以上のものにする場合でも⁠、これは同じです⁠。または⁠、創造的なプロジ⁠ェクトを世界に発信する計画の途中かもしれませんね⁠。何をするにしても⁠、スト⁠ーリ⁠ーをオンラインでどのように伝えるかによ⁠って⁠、結果は大きく変わります⁠。

専門的に聞こえるかどうかは気にせず⁠、自分らしさを出しまし⁠ょう⁠。オンラインに存在する15億を超えるWebサイトの中で⁠、あなたのサイトを特別にするのが⁠、あなただけのスト⁠ーリ⁠ーです⁠。自分の文章を読み返してもまだピンとこないなら⁠、チ⁠ャンスだと思いまし⁠ょう⁠。それは⁠、まだ改善の余地があるということですから⁠。

分かりすく堂⁠々とした語り口調を心がけ⁠、あまり考えすぎないようにしまし⁠ょう⁠。あなたのスト⁠ーリ⁠ーは⁠、進化し続けるからこそ美しいのです⁠。そしてあなたのサイトも⁠、スト⁠ーリ⁠ーとともに発展し続けます⁠。今この瞬間⁠、正しいと思えることを目標にしまし⁠ょう⁠。今後のことは⁠、き⁠っとどうにでもなります⁠。いつだ⁠ってそういうものです⁠。

掲示板




Hello⁠, World⁠!

掲示板




次へ
次へ

ブログ投稿のタ⁠イ⁠トル 2