summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorrealtradam <[email protected]>2024-06-29 00:20:29 -0400
committerrealtradam <[email protected]>2024-06-29 00:20:29 -0400
commite317bbe75a46ef3bf853cf85584bcd22ebaacf23 (patch)
tree6fbc1d6a210c5eb342ff0c90f46cb57652b8e373
parent101863b2f3c9cce50d1c15bfa5e4dc6971409b35 (diff)
downloadgameHolster-e317bbe75a46ef3bf853cf85584bcd22ebaacf23.tar.gz
gameHolster-e317bbe75a46ef3bf853cf85584bcd22ebaacf23.zip
add games page + rails auth cleanup
-rw-r--r--rails-backend/app/controllers/api/v1/auth_controller.rb89
-rw-r--r--react-frontend/src/components/GameCard.tsx43
-rw-r--r--react-frontend/src/components/Layout.tsx23
-rw-r--r--react-frontend/src/index.css92
-rw-r--r--react-frontend/src/pages/Games.tsx28
-rw-r--r--react-frontend/src/routes/index.tsx2
6 files changed, 205 insertions, 72 deletions
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 (
+ <>
+ <Link to={ link } role="button" className="block w-min pt-10 px-1">
+ <div className="gameCard">
+ <div className="gameCardWrapper">
+ <img style={{imageRendering: game.img_rendering}} src={`${import.meta.env.VITE_API_TITLE}/api/v1/games_img/realtradam/${game.titleSlug}.png?type=card`} className="gameCardCoverImg" />
+ </div>
+ <img style={{imageRendering: game.img_rendering}} src={`${import.meta.env.VITE_API_TITLE}/api/v1/games_img/realtradam/${game.titleSlug}.png?type=title`} className="gameTitleImg p-5%" />
+ <img style={{imageRendering: game.img_rendering}} src={`${import.meta.env.VITE_API_TITLE}/api/v1/games_img/realtradam/${game.titleSlug}.png?type=char`} className="gameCharacterImg" />
+ </div>
+ </Link>
+ </>
+ );
+}
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 = <IconButton onClick={loginLink} appearance="primary" color="green" icon={<Icon as={FaUser}/>}>Log In</IconButton>;
- const loggedin_element = <ButtonGroup className="flex"><Button appearance="ghost" style={{width:"100%"}}>{prop.userData.name}</Button><Button onClick={logoutLink} appearance="subtle" style={{paddingLeft:"1.4em", paddingRight:"1.4em"}}>Log Out</Button></ButtonGroup>;
+ const loggedin_element = <ButtonGroup className="flex"><Button appearance="ghost" color="red" style={{width:"100%"}}>{prop.userData.name}</Button><Button onClick={logoutLink} appearance="subtle" style={{paddingLeft:"1.4em", paddingRight:"1.4em"}}>Log Out</Button></ButtonGroup>;
console.log(prop);
return(
<>
<div className="w-screen h-screen flex border-none">
- <div className="flex flex-col h-screen overflow-y-auto overflow-x-hidden w-72 bg-stone-100">
+ <div className="flex flex-col h-screen overflow-y-auto overflow-x-hidden w-72 shrink-0 bg-stone-100">
<div className="flex flex-col bg-stone-800">
- <div className="m-4 mb-0 flex flex-col flex-grow">
- { prop.userData.name ? loggedin_element : loggedout_element }
+ <div className="m-4 mb-0 flex flex-col flex-grow">
+ { prop.userData.name ? loggedin_element : loggedout_element }
+ </div>
</div>
+ <Link to="/" role="button">
+ <div className="border-green-500 p-2 text-red-700 bg-stone-800">
+ <Icon as={GiCowboyHolster} style={{width:"100%", height:"100%"}}/>
</div>
- <div className="border-green-500 p-2 mb-2 text-red-700 bg-stone-800 rounded-b-xl"><Icon as={GiCowboyHolster} style={{width:"100%", height:"100%"}}/></div>
+ <div className="border-green-500 p-2 mb-2 text-white font-title text-2xl text-center bg-stone-800 rounded-b-xl">
+ Game Holster
+ </div>
+ </Link>
<div className="flex flex-col px-4 gap-2">
- <IconButton appearance="subtle" size="lg" icon={<Icon as={FaGamepad}/>}>Browse Games</IconButton>
+ <Link to="/games" role="button">
+ <IconButton style={{width: '100%'}} appearance="subtle" size="lg" icon={<Icon as={FaGamepad}/>}>Browse Games</IconButton>
+ </Link>
<IconButton appearance="subtle" size="lg" icon={<Icon as={GrAdd}/>}>Upload Game</IconButton>
</div>
</div>
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<GameType[]>([]);
+
+ 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) => (
+ <GameCard link={`/game/${game.titleSlug}`} game={game} key={game.id}/>
+ ));
+
+ return (
+ <>
+ <div className="w-full flex flex-wrap gap-12 justify-center">
+ { allGames }
+ </div>
+ </>
+ );
+}
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()
<Routes>
<Route path="/" element = {<Layout userData={userData} setUserData={setUserData}/>}>
<Route index element={<Home />} />
+ <Route path="/games" element={<Games />} />
<Route path="/closewindow" element={<CloseWindow />} />
</Route>
</Routes>