본문 바로가기
내일배움 과제/CH3 풋살온라인게임

프론트엔드 만들기

by GREEN나무 2024. 12. 9.
728x90

 테스트 링크 : localhost:3002

 

토큰을 사용하는게 어려웠습니다. 이젠 토큰 보내고 쓸줄 알아요

 

// DOM 로드 후 이벤트 리스너 연결
document.addEventListener('DOMContentLoaded', () => {
    const button = document.getElementById('viewCashBtn');
    button.addEventListener('click', fetchCash);
});

 

라우터 파일 기능 사용하기 (토큰 사용하기)

// 버튼 클릭 시 캐시 조회 요청
async function fetchCash() {
    const accessToken = localStorage.getItem('accessToken'); // 로그인 후 저장된 토큰을 가져옴
    const email = localStorage.getItem('email'); // //  헤더에 이메일 추가
    if (!accessToken) {
        document.getElementById('resultMessage').innerText =
            '로그인이 필요합니다.';
        return;
    }
    try {
        const response = await fetch('/api/cash', {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${accessToken}`, // 저장된 토큰을 Authorization 헤더에 추가
                'x-info': email, //  헤더에 이메일 추가
                'Content-Type': 'application/json',
            },
        });

 

body에서 전달할 내용이 있는 경우

        const response = await fetch('/api/cash/gift', {
            method: 'POST',
            headers: {
                Authorization: `Bearer ${accessToken}`, // 저장된 토큰을 Authorization 헤더에 추가
                'x-info': email, //  헤더에 이메일 추가
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ receiverEmail, amount, password }),
        });

 

라우터에서 토큰인증, body사용하기

/**O 캐시 구매API email, 캐시, 비번! **/
router.post('/cash/payment', authM, async (req, res, next) => {
    const { accountId } = req.account;
    const { buyCash, password } = req.body;
    const bCash = +buyCash;

 

더보기

Project_FO/src/routes/cash/cash.router.js

// routes/cash.router.js
import express from 'express';
import bcrypt from 'bcrypt';

import bcrypt from 'bcrypt';

import { prisma } from '../../utils/prisma/index.js';
import authM from '../../middlewares/auth.js';

const router = express.Router();

// const bcryptPassword = await bcrypt.hash(password, 10); // 생성
// const isPasswordMatch = await bcrypt.compare(password, account.password); // 비교

/** Lucky캐시API email **/
router.get('/cash/lucky', authM, async (req, res, next) => {
    const { accountId } = req.account;
    try {
        // email이 있는지 확인
        const account = await prisma.account.findFirst({
            where: { accountId },
            select: {
                email: true,
                manager: {
                    select: {
                        // 수정: `select`로 변경
                        cash: true,
                        managerId: true,
                    },
                },
            },
        });
        // 있으면
        if (!account) {
            return res
                .status(404)
                .json({ message: '존재하지 않는 Email 입니다.' });
        }

        const giftCash = Math.floor(Math.random() * 200) + 20;

        if (account.manager.cash + giftCash > 2147483640) {
            await prisma.manager.update({
                where: { managerId: account.manager.managerId },
                data: { cash: 2147483640 },
            });
            return res.status(200).json({
                message: `LUCKY!!! 캐시함이 가득 채워졌습니다.`,
                cash: giftCash,
            });
        } else {
            // originalCache는 객체 형태. originalCache -> originalCache.cash
            await prisma.manager.update({
                where: { managerId: account.manager.managerId },
                data: { cash: account.manager.cash + giftCash },
            });

            return res.status(200).json({
                message: `LUCKY!!! ${giftCash}캐시를 받았습니다.`,
                cash: giftCash,
            });
        }
    } catch (error) {
        console.error('Error lucky cash:', error);
        return res.status(500).json({ message: 'Internal server error' });
    }
});

/**O 캐시 구매API email, 캐시, 비번! **/
router.post('/cash/payment', authM, async (req, res, next) => {
    const { accountId } = req.account;
    const { buyCash, password } = req.body;
    const bCash = +buyCash;
    try {
        // 구매할 캐시가 유효한지 확인
        console.log(bCash);
        if (!bCash || bCash <= 0) {
            return res.status(400).json({
                message: '구매하려는 캐시는 0 이상의 정수를 입력해주세요.',
            });
        }

        if (+bCash > 2100000000) {
            return res.status(400).json({
                message: '21억보다 작은 캐시를 입력해주세요.',
            });
        }

        // 이메일과 비밀번호로 Account 조회
        const account = await prisma.account.findUnique({
            where: { accountId },
            select: {
                password: true,
                manager: {
                    select: { managerId: true, cash: true },
                },
            },
        });

        // 없으면
        if (!account) {
            return res
                .status(404)
                .json({ message: '존재하지 않는 Email 입니다.' });
        }
        // 비번확인
        const isPasswordMatch = await bcrypt.compare(
            password,
            account.password
        ); // (password, account.password);
        if (!isPasswordMatch) {
            return res
                .status(404)
                .json({ message: '비밀번호가 일치하지 않습니다.' });
        }

        if (account.manager.cash + bCash > 2147483640) {
            return res.status(400).json({
                message:
                    '매니저는 2,147,483,640보다 큰 캐시를 보유할 수 없습니다.',
            });
        }
        // Manager 업데이트
        await prisma.manager.update({
            where: { managerId: account.manager.managerId },
            data: { cash: account.manager.cash + bCash }, // 문자로 나왔음
        });

        return res
            .status(200)
            .json({ message: `${bCash}캐시를 결제하셧습니다.` });
    } catch (error) {
        console.error('Error fetching cash data:', error);
        return res
            .status(500)
            .json({ message: '캐시 구매 Internal server error' });
    }
});

/**O 캐시 조회API  email, 비번 추가하기 **/
router.get('/cash', authM, async (req, res, next) => {
    console.log('조회');
    const { accountId } = req.account;

    // 이메일 유효성 검사
    // if (!email || typeof email !== 'string') {
    //     return res.status(400).json({ message: 'Invalid email parameter' });
    // }
    try {
        const account = await prisma.account.findFirst({
            where: { accountId },
            select: {
                email: true,
                password: true,
                password: true,
                manager: {
                    select: {
                        cash: true,
                        managerId: true,
                    },
                },
            },
        });

        if (!account) {
            return res.status(404).json({ message: 'User not found' });
        }

        return res.status(200).json({
            data: { email: account.email, cash: account.manager.cash },
        });
    } catch (error) {
        console.error('Error fetching cash data:', error);
        return res
            .status(500)
            .json({ message: '캐시조회 Internal server error' });
    }
});

/** 1. 다른 유저에게 캐시 선물API   비번!**/
router.post('/cash/gift', authM, async (req, res, next) => {
    try {
        const accountId = req.account.accountId;
        const { receiverEmail, amount, password } = req.body;
        const parsedAmount = +amount;

        // 입력정보 확인
        if (!receiverEmail || !parsedAmount || !password) {
            return res.status(400).json({
                error: '수신자 이메일, 금액, 비밀번호를 모두 입력해주세요.',
            });
        }

        if (parsedAmount > 2100000000) {
            return res.status(400).json({
                message: '캐시는 21억보다 작은 정수를 입력해주세요.',
            });
        }

        // 송신자 정보 확인
        const sender = await prisma.account.findUnique({
            where: { accountId: Number(accountId) },
            include: {
                manager: true,
            },
        });

        if (!sender) {
            return res.status(404).json({
                error: '송신자 계정을 찾을 수 없습니다.',
            });
        }

        if (!sender.manager) {
            return res.status(404).json({
                error: '송신자의 매니저 정보를 찾을 수 없습니다.',
            });
        }

        // 비밀번호 확인
        const isPasswordMatch = await bcrypt.compare(password, sender.password);
        if (!isPasswordMatch) {
            return res.status(401).json({
                error: '비밀번호가 일치하지 않습니다.',
            });
        }

        // 수신자 확인
        const receiver = await prisma.account.findUnique({
            where: { email: receiverEmail },
            include: {
                manager: true,
            },
        });

        if (!receiver) {
            return res.status(404).json({
                error: '수신자 계정을 찾을 수 없습니다.',
            });
        }

        if (!receiver.manager) {
            return res.status(404).json({
                error: '수신자의 매니저 정보를 찾을 수 없습니다.',
            });
        }

        if (parsedAmount < 1) {
            return res.status(400).json({
                // 404 -> 400으로 변경
                error: '선물하는 금액을 1캐시 이상 입력해주세요.',
            });
        }

        // 잔액 확인
        if (sender.manager.cash < parsedAmount) {
            return res.status(400).json({
                error: '잔액이 부족합니다.',
            });
        }

        if (receiver.manager.cash + parsedAmount > 2147483640) {
            // 여기서 오류
            return res.status(400).json({
                message: '선물 캐시가 상대방의 캐시함의 빈자리보다 큽니다.',
            });
        }

        // 트랜잭션으로 캐시 이동 처리
        await prisma.$transaction([
            prisma.manager.update({
                where: { managerId: sender.manager.managerId },
                data: { cash: sender.manager.cash - parsedAmount },
            }),
            prisma.manager.update({
                where: { managerId: receiver.manager.managerId },
                data: { cash: receiver.manager.cash + parsedAmount },
            }),
        ]);

        return res.status(200).json({
            message: `${receiverEmail}님에게 ${parsedAmount}캐시를 선물했습니다.`,
        });
    } catch (error) {
        console.error('Error gifting cash:', error);
        return res
            .status(500)
            .json({ error: '캐시 선물 중 오류가 발생했습니다.' });
    }
});

/** 2. 돈 불리기 ( 행운의 룰렛)API 비번!**/
router.post('/cash/roulette', authM, async (req, res, next) => {
    console.log('여기');
    const { accountId } = req.account;
    const { betAmount, password } = req.body;
    const betingAmount = +betAmount;
    try {
        // 입력정보 유효성 확인
        const account = await prisma.account.findFirst({
            where: { accountId },
            select: {
                email: true,
                password: true,
                manager: { select: { cash: true, managerId: true } },
            },
        });
        // 이메일
        if (!account) {
            return res
                .status(404)
                .json({ message: '일치하는 이메일이 없습니다.' });
        }

        // 비번
        const isPasswordMatch = await bcrypt.compare(
            password,
            account.password
        );
        if (!isPasswordMatch) {
            return res
                .status(404)
                .json({ message: '비밀번호가 일치하지 않습니다.' });
        }

        // 캐시 보유금액 확인
        if (!Number.isInteger(betingAmount) || betingAmount < 1) {
            return res.status(404).json({
                message: '캐시는 1 이상의 정수로 적어주세요.',
            });
        }

        if (betingAmount > account.manager.cash) {
            return res.status(404).json({
                message: '보유 캐시보다 적은 금액만 걸 수 있습니다.',
            });
        }
        if (betingAmount > 2100000000) {
            return res.status(400).json({
                message: '캐시는 21억보다 작은 정수를 입력해주세요.',
            });
        }

        // 유저가 캐시를 걸면 n배로 돌려받기. 확률 설정하기
        // 0.5배: 20% |1배: 50%  |2배: 20%  |5배: 8% |10배: 1.8%  |50배: 0.2%
        const roulette = Math.random() * 100; // 0 ~ 99.9999
        let multiplyC = 0.0;

        if (roulette <= 20) {
            multiplyC = 0.5;
        } else if (roulette <= 70) {
            multiplyC = 1;
        } else if (roulette <= 90) {
            multiplyC = 2;
        } else if (roulette <= 98) {
            multiplyC = 5;
        } else if (roulette <= 99.8) {
            multiplyC = 10;
        } else {
            multiplyC = 50;
        }

        let batR = Math.floor(betingAmount * multiplyC);

        if (account.manager.cash - betingAmount + batR > 2147483640) {
            await prisma.manager.update({
                where: { managerId: account.manager.managerId },
                data: { cash: 2147483640 },
            });
            return res.status(200).json({
                message: `${multiplyC}배에 당첨되셨습니다! 캐시함이 꽉 채워졌습니다.`,
            });
        } else {
            await prisma.manager.update({
                where: { managerId: account.manager.managerId },
                data: { cash: account.manager.cash - betingAmount + batR },
            });
            return res.status(200).json({
                message: `${multiplyC}배에 당첨되셨습니다! ${batR} 캐시를 획득하셨습니다.`,
            });
        }
    } catch (error) {
        console.error('Error fetching cash data:', error);
        return res
            .status(500)
            .json({ message: '캐시 룰렛 Internal server error' });
    }
});

/**O  3. 게임 승패로 캐시 증감API  **/
//     게임 결과로 캐시 주고 뺐기
router.post('/cash/game-result', async (req, res, next) => {
    const { winnerEmail, loserEmail, result, amount } = req.body;
    console.log('루렛들어옴');
    console.log('루렛들어옴');
    try {
        if (!winnerEmail || !loserEmail || !amount || amount <= 0) {
            return res.status(400).json({
                message:
                    '승자, 패자 이메일, 경기결과, 0 이상의 보상캐시을 입력해주세요.',
            });
        }
        if (amount > 2100000000) {
            return res.status(400).json({
                message: '캐시는 21억보다 작은 정수를 입력해주세요.',
            });
        }
        if (amount > 2100000000) {
            return res.status(400).json({
                message: '캐시는 21억보다 작은 정수를 입력해주세요.',
            });
        }

        if (!result === 0 && !result === 1) {
            return res.status(400).json({
                message:
                    '승패는 무승부면 0을, 아니면 1을 정수 형태로 넣어주세요.',
            });
        }

        // 승자 데이터 확인
        const winner = await prisma.account.findFirst({
            where: { email: winnerEmail },
            select: { manager: { select: { cash: true, managerId: true } } },
        });
        if (!winner) {
            return res
                .status(404)
                .json({ message: '승자 이메일이 존재하지 않습니다.' });
        }

        // 패자 데이터 확인
        const loser = await prisma.account.findFirst({
            where: { email: loserEmail },
            select: { manager: { select: { cash: true, managerId: true } } },
        });
        if (!loser) {
            return res
                .status(404)
                .json({ message: '패자 이메일이 존재하지 않습니다.' });
        }

        // result 승패 있으면 1, 무승부면 0 을 넣기
        let winnerReward = 0;
        let loserPenalty = 0;
        if (result) {
            winnerReward = amount;
            loserPenalty = Math.max(-loser.manager.cash, -amount); // 최대 패널티는 가진 돈까지만
        } else {
            // 무승부: 배팅 금액의 절반씩 지급
            winnerReward = Math.floor(amount / 2);
            loserPenalty = Math.floor(amount / 2);
        }

        if (isNaN(winnerReward) || isNaN(loserPenalty)) {
            throw new Error('캐시 계산1 중 오류가 발생했습니다.');
        }

        const winnerCashUpdate = winner.manager.cash + winnerReward;
        const loserCashUpdate = loser.manager.cash + loserPenalty;

        if (isNaN(winnerCashUpdate) || isNaN(loserCashUpdate)) {
            throw new Error('캐시 계산2 중 오류가 발생했습니다.');
        }

        // 데이터 업데이트
        await prisma.manager.update({
            where: { managerId: winner.manager.managerId },
            data: { cash: winnerCashUpdate },
        });
        await prisma.manager.update({
            where: { managerId: loser.manager.managerId },
            data: { cash: loserCashUpdate },
        });

        if (result) {
            return res.status(200).json({
                message: '경기보상을 받으세요!',
                gameResult: `${winnerEmail} 승리`,
                details: [
                    { email: winnerEmail, change: `+${winnerReward} 캐시` },
                    { email: loserEmail, change: `${loserPenalty} 캐시` },
                ],
            });
        } else {
            return res.status(200).json({
                message: '경기보상을 받으세요!',
                gameResult: '무승부',
                details: [
                    { email: winnerEmail, change: `+${winnerReward} 캐시` },
                    { email: loserEmail, change: `+${loserPenalty} 캐시` },
                ],
            });
        }
    } catch (error) {
        console.error('Error processing game result:', error);
        return res
            .status(500)
            .json({ message: '캐시 승패 Internal server error' });
    }
});

export default router;

 

Project_FO/public/cash/cash.html

<!-- V:\Sparta\Team\ch3_Futsal\cash\Project_FO\public\cash\cash.html -->
<!-- http://127.0.0.1:3002/cash/cash.html -->
<!DOCTYPE html>
<html lang="ko">

<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="cashScript.js"></script>
</head>

<body>


    <div class="container">
        <header>
            <h1>캐시 상점</h1>
        </header>
        <main>
            <section id="cash-actions">

                <section id="output">
                    <h5>캐시상점에 오신걸 환영합니다!</h5>
                    <div id="resultMessage"></div>
                </section>

                <div class="form-group">
                    <button id="viewCashBtn">My 캐시 조회</button>
                </div>
                <div class="form-group">
                    <button id="luckyCashBtn">Lucky 캐시</button>
                </div>
                <div class="form-group">
                    <!--캐시구매-->
                    <h2></h2>
                    <h1>캐시구매</h1>
                    <label for="buyCashInput">캐시 가격:</label>
                    <input type="number" id="buyCashInput" required />
                    <label for="passwordInput">비밀번호:</label>
                    <input type="password" id="passwordBInput" required />
                    <button id="buyCashBtn">캐시 구매</button>

                </div>
                <div class="form-group">
                    <!--캐시선물-->
                    <h2></h2>
                    <h1>캐시선물</h1>
                    <!-- <label for="senderEmail">My 이메일:</label>
                    <input type="senderEmail" id="senderEmail" required /> -->
                    <label for="receiverEmail">받는 사람 이메일:</label>
                    <input type="receiverEmail" id="receiverEmailInput" required />
                    <label for="amount">선물 캐시:</label>
                    <input type="amount" id="amountGInput" required />
                    <label for="password">비밀번호:</label>
                    <input type="password" id="passwordGInput" required />
                    <button id="giftCashBtn">캐시 선물하기</button>
                </div>
                <div class="form-group">
                    <!--룰렛-->
                    <h2></h2>
                    <h1>룰렛 캐시</h1>
                    <label for="amount">캐시 배팅:</label>
                    <input type="amount" id="amountRInput" required />
                    <label for="password">비밀번호:</label>
                    <input type="password" id="passwordRInput" required />

                    <button id="playRouletteBtn">룰렛 돌리기</button>
                </div>
            </section>

            <section id="action-forms" style="display: none;">
                <!-- Form templates will be dynamically inserted here -->
            </section>


        </main>

    </div>


</body>

</html>

Project_FO/public/cash/cashScript.js

// DOM 로드 후 이벤트 리스너 연결
document.addEventListener('DOMContentLoaded', () => {
    const button = document.getElementById('viewCashBtn');
    button.addEventListener('click', fetchCash);
});

document.addEventListener('DOMContentLoaded', () => {
    const button = document.getElementById('luckyCashBtn');
    button.addEventListener('click', fetchLuck);
});

document.addEventListener('DOMContentLoaded', () => {
    const button = document.getElementById('buyCashBtn');
    button.addEventListener('click', fetchBuy);
});

document.addEventListener('DOMContentLoaded', () => {
    const button = document.getElementById('giftCashBtn');
    button.addEventListener('click', fetchGift);
});

document.addEventListener('DOMContentLoaded', () => {
    const button = document.getElementById('playRouletteBtn');
    button.addEventListener('click', fetchRoulett);
});

// 버튼 클릭 시 캐시 조회 요청
async function fetchCash() {
    const accessToken = localStorage.getItem('accessToken'); // 로그인 후 저장된 토큰을 가져옴
    const email = localStorage.getItem('email'); // //  헤더에 이메일 추가
    if (!accessToken) {
        document.getElementById('resultMessage').innerText =
            '로그인이 필요합니다.';
        return;
    }
    try {
        const response = await fetch('/api/cash', {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${accessToken}`, // 저장된 토큰을 Authorization 헤더에 추가
                'x-info': email, //  헤더에 이메일 추가
                'Content-Type': 'application/json',
            },
        });

        if (!response.ok) {
            // 에러 메시지 출력
            const errorData = await response.json();
            document.getElementById('resultMessage').innerText =
                `Error: ${errorData.message}`;
            return;
        }

        const data = await response.json();
        document.getElementById('resultMessage').innerText =
            `이메일: ${data.data.email}, 캐시: ${data.data.cash}`;
    } catch (error) {
        console.error('Fetch error:', error);
        document.getElementById('resultMessage').innerText =
            '서버와 연결할 수 없습니다.';
    }
}

async function fetchLuck() {
    const accessToken = localStorage.getItem('accessToken'); // 로그인 후 저장된 토큰을 가져옴
    const email = localStorage.getItem('email'); // //  헤더에 이메일 추가
    if (!accessToken) {
        document.getElementById('resultMessage').innerText =
            '로그인이 필요합니다.';
        return;
    }
    try {
        const response = await fetch('/api/cash/lucky', {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${accessToken}`, // 저장된 토큰을 Authorization 헤더에 추가
                'x-info': email, //  헤더에 이메일 추가
                'Content-Type': 'application/json',
            },
        });

        if (!response.ok) {
            // 에러 메시지 출력
            const errorData = await response.json();
            document.getElementById('resultMessage').innerText =
                `Error: ${errorData.message}`;
            return;
        }

        const data = await response.json();
        document.getElementById('resultMessage').innerText = `${data.message}`; // 수정
    } catch (error) {
        console.error('Fetch error:', error);
        document.getElementById('resultMessage').innerText =
            '서버와 연결할 수 없습니다.';
    }
}

// + body
async function fetchBuy() {
    const accessToken = localStorage.getItem('accessToken'); // 로그인 후 저장된 토큰을 가져옴
    const email = localStorage.getItem('email'); // //  헤더에 이메일 추가
    if (!accessToken) {
        document.getElementById('resultMessage').innerText =
            '로그인이 필요합니다.';
        return;
    }
    const buyCash = document.getElementById('buyCashInput').value; // 입력된 buyCash 값
    const password = document.getElementById('passwordBInput').value; // 입력된 password 값

    try {
        const response = await fetch('/api/cash/payment', {
            method: 'POST',
            headers: {
                Authorization: `Bearer ${accessToken}`, // 저장된 토큰을 Authorization 헤더에 추가
                'x-info': email, //  헤더에 이메일 추가'Content-Type': 'application/json',
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ buyCash, password }),
        });

        if (!response.ok) {
            // 에러 메시지 출력
            const errorData = await response.json();
            document.getElementById('resultMessage').innerText =
                `Error: ${errorData.message}`;
            return;
        }

        const data = await response.json();
        document.getElementById('resultMessage').innerText = `${data.message}`;
    } catch (error) {
        console.error('Fetch error:', error);
        document.getElementById('resultMessage').innerText =
            '서버와 연결할 수 없습니다.';
    }
}

// + body
async function fetchGift() {
    const accessToken = localStorage.getItem('accessToken'); // 로그인 후 저장된 토큰을 가져옴
    const email = localStorage.getItem('email'); // //  헤더에 이메일 추가
    if (!accessToken) {
        document.getElementById('resultMessage').innerText =
            '로그인이 필요합니다.';
        return;
    }
    const receiverEmail = document.getElementById('receiverEmailInput').value; // 입력된 buyCash 값
    const amount = document.getElementById('amountGInput').value; // 입력된 buyCash 값
    const password = document.getElementById('passwordGInput').value; // 입력된 password 값

    try {
        const response = await fetch('/api/cash/gift', {
            method: 'POST',
            headers: {
                Authorization: `Bearer ${accessToken}`, // 저장된 토큰을 Authorization 헤더에 추가
                'x-info': email, //  헤더에 이메일 추가
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ receiverEmail, amount, password }),
        });

        if (!response.ok) {
            // 에러 메시지 출력
            const errorData = await response.json();
            document.getElementById('resultMessage').innerText =
                `Error: ${errorData.message}`;
            return;
        }

        const data = await response.json();
        document.getElementById('resultMessage').innerText = `${data.message}`;
    } catch (error) {
        console.error('Fetch error:', error);
        document.getElementById('resultMessage').innerText =
            '서버와 연결할 수 없습니다.';
    }
}

// + body
async function fetchRoulett() {
    const accessToken = localStorage.getItem('accessToken'); // 로그인 후 저장된 토큰을 가져옴
    const email = localStorage.getItem('email'); // //  헤더에 이메일 추가

    if (!accessToken) {
        document.getElementById('resultMessage').innerText =
            '로그인이 필요합니다.';
        return;
    }
    const betAmount = document.getElementById('amountRInput').value; // 입력된 buyCash 값
    const password = document.getElementById('passwordRInput').value; // 입력된 password 값
    try {
        const response = await fetch('/api/cash/roulette', {
            method: 'POST',
            headers: {
                Authorization: `Bearer ${accessToken}`, // 저장된 토큰을 Authorization 헤더에 추가
                'x-info': email, //  헤더에 이메일 추가
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ betAmount, password }),
        });

        if (!response.ok) {
            // 에러 메시지 출력
            const errorData = await response.json();
            document.getElementById('resultMessage').innerText =
                `Error: ${errorData.message}`;
            return;
        }

        const data = await response.json();
        document.getElementById('resultMessage').innerText = `${data.message}`;
    } catch (error) {
        console.error('Fetch error:', error);
        document.getElementById('resultMessage').innerText =
            '서버와 연결할 수 없습니다.';
    }
}

Project_FO/public/cash/ styles.css

/* 구글 폰트 import url */
@import url('https://fonts.googleapis.com/css2?family=Black+Han+Sans&family=Do+Hyeon&family=Gowun+Dodum&family=Orbit&family=Song+Myung&display=swap');

.header{
    height: 200px;
}
body {
    font-family: 'Orbit', sans-serif;
    background-color: #f4f4f4;
    display: flex; /* Flexbox 레이아웃 */
    flex-direction: column;
    /* height: 100vh; */
    margin: 200px;
}

.container {
    font-family: 'Orbit', sans-serif;
    background: rgb(255, 255, 255);
    padding: 50px; /* 박스 내부 여백 */
    border-radius: 8px; /* 둥근 모서리 */
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* 그림자 효과 */
    display: flex;
    flex-direction: column; /* 세로 정렬 */
    justify-content: center; /* 수직 중앙 정렬 */
    align-items: center; /* 수평 중앙 정렬 */
    width: 100%;
    height: 100%;
    /* max-width: 400px; 박스 최대 너비 */
    margin: auto; /* 화면 중앙 정렬 */
}

h1 {
    text-align: center;
    margin-bottom: 20px; /* 제목 아래 여백 */
}

#cash-actions{       
        position: relative; /* 요소를 이동시키기 위해 relative를 사용 */
        padding: 10px; 
}
#output{
    border-radius: 8px; /* 둥근 모서리 */
    background-color: #ecfce8;
    padding: 5px 0; 
    text-align: center;  
    margin-bottom: 20px;
}
.form-group {
    margin-bottom: 15px;
    width: 100%; /* 입력 필드와 버튼 너비를 박스에 맞춤 */
}

label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold; /* 라벨 텍스트 강조 */
}

input {
    width: 100%;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
    box-sizing: border-box;
    margin-top: 10px;
    margin-bottom: 10px;
}

button {
    font-family: 'Orbit', sans-serif;
    width: 100%;
    padding: 10px;
    background-color: #28a745;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
}

/* 버튼 안의 링크 스타일 제거 */
button a {
    text-decoration: none; /* 밑줄 제거 */
    color: inherit; /* 부모 요소의 글자색을 따름 */
}

/* 버튼을 클릭했을 때 글자색 유지 */
button a:visited {
    color: inherit; /* 방문 후에도 글자색 유지 */
}

button:hover {
    background-color: #218838;
}

#message {
    margin-top: 20px;
    text-align: center;
}

 

 

더보기

프론트엔드를 만들 때, refresh token으로 access token을 갱신하기 위해 헤더를 설정하고 데이터를 불러오던 과정이

세션 DB와 localStorage를 적절히 사용해서 구현을 해야 했는데

처음엔 방법을 몰라서 좀 헤맸습니다
알고 보니 페이지가 이동될 때마다 헤더가 날아가서 localStorage가 필요한 거더라고요

그래서 api를 요청할 때마다 email을 다시 헤더에 넣어주는 작업을 fetch를 통해

수행했더니 api와 잘 연동이 되었습니다

이제는 access token이 만료가 되어도 email을 통해 사용자의 refresh token을 db에서 읽어올 수 있습니다

refresh token이 유효하다면 access token이 갱신되는 방식으로요

'내일배움 과제 > CH3 풋살온라인게임' 카테고리의 다른 글

CH3 풋살 온라인 프로젝트 발표  (1) 2024.12.09
발표회 준비  (0) 2024.12.06
튜터님 코드리뷰  (1) 2024.12.06
1차 머지 후 오류 수정  (0) 2024.12.05
캐시 기능 추가시 기능 추가  (0) 2024.12.04