Challenge:

Store the profile photo as the original canvas’s URL ⇒ Get the brightness of image ⇒ get the pixels ⇒draw other words onto it

Gohai’s Code:

https://editor.p5js.org/gohai/sketches/62ntMs7t2\

Done:

MBTI 每个character解释instructions

Count age

//Age Calculation

function getPetAge() {
  const value = document.getElementById("birthDisplay").value;
  if (!value) return "未知";

  const birth = new Date(value);
  const today = new Date();

  const totalMonths =
    (today.getFullYear() - birth.getFullYear()) * 12 +
    (today.getMonth() - birth.getMonth());

  const years = Math.floor(totalMonths / 12);
  const months = totalMonths % 12;

  if (years === 0) {
    return `${months}个月`;
  } else if (months === 0) {
    return `${years}岁`;
  } else {
    return `${years}.${months}岁`;
  }
}

add hukou

Store the username ⇒ petname of “who likes you” to the profile

//script.js
// like 时发送到服务器
function like() {
  if (currentIndex < profiles.length) {
    const likedUsername = profiles[currentIndex].username;

    fetch("/like", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        likerUsername: currentUser.username,
        likerPetName: currentUser.name,
        likedUsername: likedUsername,
      }),
    });
  }
  currentIndex++;
  showProfile();
}

//server.js

// POST /like — 记录一个 like
app.post("/like", function (req, res) {
  const { likerUsername, likerPetName, likedUsername } = req.body;

  // 找到被 like 的 profile
  let likedProfile = profiles.find((p) => p.username === likedUsername);
  if (!likedProfile)
    return res.status(404).json({ error: "Profile not found" });

  // 初始化 likes 数组
  if (!likedProfile.likes) likedProfile.likes = [];

  // 避免同一人重复 like
  if (!likedProfile.likes.includes(likerPetName)) {
    likedProfile.likes.push(likerPetName);
  }

  // 保存到文件
  fs.writeFileSync("profiles.json", JSON.stringify(profiles, null, 2));
  res.json({ success: true, likesCount: likedProfile.likes.length });
});

Profile Scrolling Debug: 画图环节的touchMoved 拦截了滑动,所以要用

  // 只有在画图页面才拦截触摸
  const photoPage = document.getElementById("profile-photo");
  if (!photoPage.classList.contains("active")) {
    return true; // 👈 其他页面放行,允许正常滚动
  }

进入app的时候 会被通知被谁喜欢了:

Count Likes/Dislikes and add to the database

// script.js
// 进入 app 时检查通知
function checkNotifications() {
  if (!currentUser) return;

  fetch(`/notifications/${currentUser.username}`)
    .then((res) => res.json())
    .then((data) => {
      if (data.likesCount > 0) {
        alert(
          `💗 你有 ${data.likesCount} 个宠物喜欢你!\n来自: ${data.likedBy.join(", ")}`,
        );
      }
    });
}

// server.js
// GET /notifications/:username — 获取被 like 的通知
app.get("/notifications/:username", function (req, res) {
  const username = req.params.username;
  const profile = profiles.find((p) => p.username === username);
  if (!profile) return res.status(404).json({ error: "Not found" });

  res.json({
    likesCount: profile.likes ? profile.likes.length : 0,
    likedBy: profile.likes || [],
  });
});

Login: 密码/username错了通知, 用它们判断是否是login还是register After Login, distinguish who has already registered and enter the swiping page directly. If username is right but password is wrong ⇒ Give a hint

function handleLogin() {
  const username = document.getElementById("username").value.trim();
  const password = document.getElementById("password").value.trim();

  if (!username) return alert("请输入用户名 / Please enter username");

  // 从服务器拿所有 profiles,检查是否已存在
  fetch("/profiles")
    .then((res) => res.json())
    .then((data) => {
      const existing = data.find(
        (p) => p.username === username && p.password === password,
      );

      if (existing) {
        currentUser = existing;
        // 老用户 → 直接进入 swipe
        checkNotifications();
        createSwipeCard();
      } else {
        const userExists = data.find((p) => p.username === username);
        if (userExists) {
          // username 存在但密码错
          alert("密码错误 / Wrong password");
        } else {
          // 新用户 → 走注册流程
          goTo("profile-name");
        }
      }
    });
}