DEV Community

Cover image for Netlify Dynamic Site Challenge: Motizen, a treasure hunt game
Sergo
Sergo

Posted on • Edited on

1

Netlify Dynamic Site Challenge: Motizen, a treasure hunt game

This is a submission for the Netlify Dynamic Site Challenge: Build with Blobs.

First of all, I want to apologize. Both to myself and to the community. Unfortunately, I couldn't and didn't have time to implement everything I wanted. I didn't estimate my strength and time. And this is a very big mistake. But I always remember that many smart people said that it's better late than never. Or it's better to participate than not to participate.

What I Built

I wanted to surprise you with a game where each user would uncover pieces of a picture and find various treasures. Every day, piece by piece. But since I don't have enough experience, and I didn't work closely with Netlify, it turned out the way it did.

First of all, when you go to the site, don't be scared. Yes, there is a registration. 😅 I implemented it with Netlify Integrity. The game was supposed to show players who found treasures. But I didn't have time to implement this.

Demo

Mista

You can try the game here.
Attention! Please do not click too quickly and too much! I didn't implement serverless functions very well.😭😥

Platform Primitives

I implemented two functions, loadGameState, saveGameState, with which you can save the game state using Netlify Blobs as storage. And I did it through Netlify Function Serverless.

async function loadGameState(gameStateBlobId) {
    return fetch(`/.netlify/functions/load-game-state?blobID=${gameStateBlobId}`, {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json',
        }
    })
    .then(response => {
        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }
        return response.json();
    })
    .then(result => {
      const gameState = JSON.parse(result.gameState);
      console.log('Game state loaded successfully: ', gameState);
      return gameState;
    })
    .catch(error => {
      console.log('Error in loading game state: ', error);
      throw error;
    });
}

async function saveGameState(gameState) {
    const json = JSON.stringify(gameState);

    return fetch('/.netlify/functions/save-game-state', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: json
    })
    .then(response => {
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
        return response.json();
    })
    .then(result => {
      console.log('Game state saved successfully: ', result)
      return result;
    })
    .then(result => {
        localStorage.setItem('gameStateBlobId', result.blobID);
    })
    .catch(error => {
      console.log('Error in saving game state: ', error);
      throw error;
    });
}
Enter fullscreen mode Exit fullscreen mode

This is a serverless function for load-game-state.mjs:

import { getStore } from '@netlify/blobs';

exports.handler = async function(event, context) {
    const siteID = process.env.NETLIFY_SITE_ID;
    const token = process.env.NETLIFY_TOKEN;
    const store = getStore({ siteID, token, name: 'my-store' });

    if (event.httpMethod !== 'GET') {
      return { statusCode: 405, body: 'Method Not Allowed' };
    }

    const blobID = event.queryStringParameters.blobID;
    if (!blobID) {
      return { statusCode: 400, body: JSON.stringify({ message: "BlobID is required" }) };
    }

    let buffer;
    try {
      buffer = await store.get(blobID);
    } catch (error) {
      console.error("Error fetching blob:", error);
      return { statusCode: 500, body: JSON.stringify({ message: "Error fetching game state" }) };
    }

    if (!buffer) {
      return { statusCode: 404, body: JSON.stringify({ message: "Game state not found" }) };
    }

    const gameState = buffer.toString();

    return {
      statusCode: 200,
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ gameState })
    };
};
Enter fullscreen mode Exit fullscreen mode

And this is how I implemented Netlify Integrity (maybe, someone it will helpful):

'use client'

import netlifyIdentity from 'netlify-identity-widget';

export default function Home() {

...

    useEffect(() => {
      netlifyIdentity.init();

      const handleLogin = (currentUser) => {
        netlifyIdentity.open();
        setIsLoggedIn(true);
        setPlayerName(currentUser.user_metadata.full_name || currentUser.email);
      };

      const handleLogout = () => {
        setIsLoggedIn(false);
        setPlayerName('');
        netlifyIdentity.logout(); // выход из системы
      };

      netlifyIdentity.on('login', handleLogin);
      netlifyIdentity.on('logout', handleLogout);

      if (netlifyIdentity.currentUser()){
        handleLogin(netlifyIdentity.currentUser());
      }

      return () => {
        netlifyIdentity.off('login', handleLogin);
        netlifyIdentity.off('logout', handleLogout);
      };
    }, []); 

    return (
      <main className={styles.main}>
        <ImageUploader onFileSelect={(selectedFile) => setFile(selectedFile)} setName={(name) => {setUserName(name); setPlayerName(name);}} />
        <CanvasComponent processImage={processImage} />
        <div ref={nameRef}>{playerName}</div>{/* Div для отображения имен */}
        {isLoggedIn ? (
          <div className={styles.userIdentity}>
            {playerName}
            <button onClick={() => netlifyIdentity.logout()}>Logout</button>
          </div>
        ) : (
          <button onClick={() => netlifyIdentity.open()}>Login / Sign Up</button>
        )}
      </main>
    );
}
Enter fullscreen mode Exit fullscreen mode

This is not the End

In this project I used Next.js, Netlify Blobs Store, Netlify Integrity, Canvas API, Netlify Serverless and deployed on Netlify.
It was hard, but very interesting. Thank you for this challenge!

Griffith

Retry later

Top comments (0)

Retry later
Retry later