From e317bbe75a46ef3bf853cf85584bcd22ebaacf23 Mon Sep 17 00:00:00 2001 From: realtradam Date: Sat, 29 Jun 2024 00:20:29 -0400 Subject: add games page + rails auth cleanup --- .../app/controllers/api/v1/auth_controller.rb | 89 ++++++--------------- react-frontend/src/components/GameCard.tsx | 43 ++++++++++ react-frontend/src/components/Layout.tsx | 23 ++++-- react-frontend/src/index.css | 92 +++++++++++++++++++++- react-frontend/src/pages/Games.tsx | 28 +++++++ react-frontend/src/routes/index.tsx | 2 + 6 files changed, 205 insertions(+), 72 deletions(-) create mode 100644 react-frontend/src/components/GameCard.tsx create mode 100644 react-frontend/src/pages/Games.tsx diff --git a/rails-backend/app/controllers/api/v1/auth_controller.rb b/rails-backend/app/controllers/api/v1/auth_controller.rb index cfcb253..a5dfe7c 100644 --- a/rails-backend/app/controllers/api/v1/auth_controller.rb +++ b/rails-backend/app/controllers/api/v1/auth_controller.rb @@ -5,97 +5,46 @@ class Api::V1::AuthController < ApplicationController class << self end + # returns data about the user that is logged in + # e.g username def data if !cookies[:session].nil? - puts "Logged in" - puts cookies[:session] - #render json: Api::V1::AuthController.user_table[cookies[:session]] result = User.find_by(access_token_digest: cookies[:session]) render json: result else - puts "Not logged in" render json: { info: "Not logged in" }, status: 401 end end + + # user logs in through github + # github redirects them to this endpoint with the token in the url as query params + # we need to use this token to exchange with github for user info(e.g username) def callback - # user logs in through github - # github redirects them to this endpoint with the token in the url as query params - # we need to use this token to exchange with github for user info(i.e username) - #puts "Code: #{params[:code]}" # this is the github token - #puts ENV["GITHUB_CLIENT_SECRET"] - #puts ENV["GITHUB_CLIENT_ID"] access_token = get_access_token(params[:code]) user_data = JSON.parse(get_github_user_data(access_token)) - #puts "------------------------- USER DATA: ------------------------- " - #pp user_data id = user_data['id'].to_s - #puts "id: #{id}, at: #{access_token}" access_token_digest = BCrypt::Password.create(access_token) - #cookies[:session] = access_token_digest cookies[:session] = { value: access_token_digest, - #domain: :all, - #same_site: :none, - #secure: true + secure: true } - #user_params = { - # # access_token_digest: hashed_token, - # user_data: user_data - #} - #puts "USER DATA HERE NERD" - #puts user_data.class user = User.find_or_create_by(identifier: id) user.user_data = user_data user.access_token_digest = access_token_digest user.user_name = user_data["login"] user.save - #redirect_to 'http://localhost:5173/', allow_other_host: true redirect_to "#{ENV['ROOT_DOMAIN']}/closewindow", allow_other_host: true end + def logout - if !cookies[:session].nil? - puts cookies[:session] - cookies.delete :session - else - puts "cookies not found" - end - #cookies.delete :session, domain: 'localhost' - #redirect_to "#{ENV['ROOT_DOMAIN']}", allow_other_host: true + cookies.delete :session end private - def get_github_user_data(access_token) - uri = URI("https://api.github.com/user") - headers = { Authorization: "Bearer #{access_token}" } - response = Net::HTTP.get( - uri, - headers - ) - puts "Response Body" - puts response - #if response.is_a?(Net::HTTPSuccess) - #if response.body.nil? - result = response - if !result["error"].nil? - puts "Error: #{result["error"]}" - puts response - # we had an error - # TODO - else - puts "huh?" if result.nil? - return result - end - #else - # puts "Error(body nil)" - # something went wrong? - # TODO - #end - end - + # used by callback method def get_access_token(github_user_code) uri = URI("https://github.com/login/oauth/access_token?client_id=#{ENV["GITHUB_CLIENT_ID"]}&client_secret=#{ENV["GITHUB_CLIENT_SECRET"]}&code=#{github_user_code}") - #uri = URI('https://github.com/login/oauth/access_token') headers = {Accept: 'application/json'} response = Net::HTTP.post( uri, @@ -109,9 +58,21 @@ class Api::V1::AuthController < ApplicationController else return result["access_token"] end - else - # something went wrong? - # TODO + end + end + # used by callback method + def get_github_user_data(access_token) + uri = URI("https://api.github.com/user") + headers = { Authorization: "Bearer #{access_token}" } + response = Net::HTTP.get( + uri, + headers + ) + puts "Response Body" + puts response + result = response + if result["error"].nil? + return result end end end diff --git a/react-frontend/src/components/GameCard.tsx b/react-frontend/src/components/GameCard.tsx new file mode 100644 index 0000000..4367977 --- /dev/null +++ b/react-frontend/src/components/GameCard.tsx @@ -0,0 +1,43 @@ +import { Link } from "react-router-dom"; + +export type ImageRendering = "auto" | "crisp-edges" | "pixelated"; +export type Tag = { + id: number, + tag_type: string, + name: string, +}; +export type GameType = { + id: number, + title: string, + titleSlug: string, + description: string, + github_link: string, + img_rendering: ImageRendering, + status: string, + order: number, + created_at: string, + updated_at: string, + user_id: number, + tags: Tag[], + card_img: string, + char_img: string, + title_img: string, +}; +export type GameCardProps = { link: string, game: GameType }; + +export default function GameCard ({ link, game }: GameCardProps) +{ + return ( + <> + +
+
+ +
+ + +
+ + + ); +} diff --git a/react-frontend/src/components/Layout.tsx b/react-frontend/src/components/Layout.tsx index db31b55..274e579 100644 --- a/react-frontend/src/components/Layout.tsx +++ b/react-frontend/src/components/Layout.tsx @@ -1,5 +1,5 @@ import { Dispatch } from 'react'; -import { Outlet, useNavigate } from "react-router-dom"; +import { Outlet, Link, useNavigate } from "react-router-dom"; import { IconButton, Button, ButtonGroup } from 'rsuite'; import { Icon } from '@rsuite/icons'; import { FaUser } from "react-icons/fa6"; @@ -28,22 +28,31 @@ export default function Layout(prop : { userData: userData, setUserData : Dispat const loggedout_element = }>Log In; - const loggedin_element = ; + const loggedin_element = ; console.log(prop); return( <>
-
+
-
- { prop.userData.name ? loggedin_element : loggedout_element } +
+ { prop.userData.name ? loggedin_element : loggedout_element } +
+ +
+
-
+
+ Game Holster +
+
- }>Browse Games + + }>Browse Games + }>Upload Game
diff --git a/react-frontend/src/index.css b/react-frontend/src/index.css index ac216f5..382c958 100644 --- a/react-frontend/src/index.css +++ b/react-frontend/src/index.css @@ -2,7 +2,97 @@ @tailwind components; @tailwind utilities; +/* debug class */ * { - /*border: 1px solid red;*/ + border: 1px solid red; } +@layer components { + .gameCard { + aspect-ratio: 5/7; + width: 18.75em; /*300px;*/ + perspective: 2500px; + + @apply relative flex justify-center items-end; + } + + .gameCardCoverImg { + + @apply w-full h-full object-cover rounded-md; + } + + .gameCardWrapper { + transition: all 0.5s; + z-index: -1; + box-shadow: -15px 15px 32px -8px rgba(0, 0, 0, 0.75); + + @apply absolute w-full h-full rounded-md; + } + + .gameCard:hover .gameCardWrapper { + transform: perspective(900px) translateY(-5%) rotateX(25deg) translateZ(0); + box-shadow: -10px 35px 32px -8px rgba(0, 0, 0, 0.75); + } + + .gameCardWrapper::before, + .gameCardWrapper::after { + content: ""; + transition: all 0.5s; + + @apply opacity-0 w-full h-20 absolute left-0 rounded-md; + } + + .gameCardWrapper::before { + background-image: linear-gradient( + to top, + transparent 46%, + rgba(12, 13, 19, 0.5) 68%, + rgba(12, 13, 19) 97% + ); + + @apply top-0 h-full rounded-md; + } + + .gameCardWrapper::after { + background-image: linear-gradient( + to bottom, + transparent 46%, + rgba(12, 13, 19, 0.5) 68%, + rgba(12, 13, 19) 97% + ); + + @apply bottom-0 opacity-100 rounded-md; + } + + .gameCard:hover .gameCardWrapper::before, + .gameCardWrapper::after { + + @apply opacity-100; + } + + .gameTitleImg { + padding: 5%; + transition: transform 0.5s; + + @apply w-full max-h-40 object-contain; + } + + .gameCard:hover .gameTitleImg { + transform: translate3d(0%, -50px, 100px); + } + + .gameCharacterImg { + transition: all 0.5s; + z-index: -1; + + @apply w-full max-h-80 object-contain opacity-0 absolute; + } + + .gameCard:hover .gameCharacterImg { + transform: translate3d(0%, -30%, 100px); + + @apply opacity-100; + } +} + + diff --git a/react-frontend/src/pages/Games.tsx b/react-frontend/src/pages/Games.tsx new file mode 100644 index 0000000..2a9b23a --- /dev/null +++ b/react-frontend/src/pages/Games.tsx @@ -0,0 +1,28 @@ +import { useState, useEffect } from "react"; +import GameCard from "../components/GameCard"; + +export default function Games () { + const [games, setGames] = useState([]); + + useEffect(() => { + const url = `${import.meta.env.VITE_API_TITLE}/api/v1/games`; + fetch(url).then((response) => { + if (response.ok) { + return response.json(); + } + throw new Error("Network response was not ok."); + }).then((response) => setGames(response)); //.catch(() => navigate("/")); + }, []); + + const allGames = games.map((game) => ( + + )); + + return ( + <> +
+ { allGames } +
+ + ); +} diff --git a/react-frontend/src/routes/index.tsx b/react-frontend/src/routes/index.tsx index 6876ce5..9b3d599 100644 --- a/react-frontend/src/routes/index.tsx +++ b/react-frontend/src/routes/index.tsx @@ -1,6 +1,7 @@ import { useState, useEffect } from "react"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import Home from "../pages/Home"; +import Games from "../pages/Games"; import Layout from "../components/Layout"; import CloseWindow from "../pages/CloseWindow"; @@ -34,6 +35,7 @@ export default function Index() }> } /> + } /> } /> -- cgit v1.2.3