merge with main

This commit is contained in:
Jae Young Ahn 2025-04-22 12:14:38 -07:00
commit f906d5fdce
16 changed files with 413 additions and 52 deletions

26
.dockerignore Normal file
View file

@ -0,0 +1,26 @@
# flyctl launch added from .gitignore
# Logs
**\logs
**\*.log
**\npm-debug.log*
**\yarn-debug.log*
**\yarn-error.log*
**\pnpm-debug.log*
**\lerna-debug.log*
**\node_modules
**\dist
**\dist-ssr
**\*.local
# Editor directories and files
**\.vscode\*
!**\.vscode\extensions.json
**\.idea
**\.DS_Store
**\*.suo
**\*.ntvs*
**\*.njsproj
**\*.sln
**\*.sw?
fly.toml

18
.github/workflows/fly-deploy.yml vendored Normal file
View file

@ -0,0 +1,18 @@
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/
name: Fly Deploy
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
concurrency: deploy-group # optional: ensure only one action runs at a time
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

27
Dockerfile Normal file
View file

@ -0,0 +1,27 @@
# Build Stage
FROM node:18 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Serve Stage
FROM nginx:stable-alpine
# Copy built React files into nginx public folder
COPY --from=build /app/dist /usr/share/nginx/html
# Remove default nginx config
RUN rm /etc/nginx/conf.d/default.conf
# Add your own nginx config
COPY nginx.conf /etc/nginx/conf.d
# Expose port 80
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

42
fly.toml Normal file
View file

@ -0,0 +1,42 @@
# fly.toml app configuration file generated for bytecamp-web on 2025-04-21T13:40:11-07:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#
app = 'bytecamp-web'
primary_region = 'sea'
[build]
[env]
PORT = '8080'
[http_service]
internal_port = 80
force_https = true
auto_stop_machines = 'stop'
auto_start_machines = true
min_machines_running = 0
processes = ['app']
[[services]]
protocol = 'tcp'
internal_port = 8080
[[services.ports]]
port = 80
handlers = ['http']
[[services.ports]]
port = 443
handlers = ['tls', 'http']
[[services.tcp_checks]]
interval = '10s'
timeout = '2s'
grace_period = '5s'
[[vm]]
memory = '1gb'
cpu_kind = 'shared'
cpus = 1

11
nginx.conf Normal file
View file

@ -0,0 +1,11 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri /index.html;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

View file

@ -17,6 +17,9 @@ const Header = () => {
<li> <li>
<Link to="/login">Login</Link> <Link to="/login">Login</Link>
</li> </li>
<li>
<Link to="/assignment">Assignment</Link>
</li>
</ul> </ul>
</nav> </nav>
</header> </header>

View file

@ -1,19 +1,41 @@
import React from 'react' import React from "react";
import '../scss/styles.scss' import "../scss/styles.scss";
import '../scss/components/_navbar.scss' import "../scss/components/_navbar.scss";
import { Link } from "react-router-dom";
const Navbar = () => { const Navbar = () => {
return ( return (
<nav className="navbar"> <nav className="navbar">
<div className="navbar__logo">MyApp</div> <div className="navbar__logo">MyApp</div>
<ul className="navbar__links"> <ul className="navbar__links">
<li><a href="/" className="navbar__link">Home</a></li> <li>
<li><a href="/notebook" className="navbar__link">NoteBook</a></li> <Link to="/" className="navbar__link">
<li><a href="/assignment" className="navbar__link">Assignment</a></li> Home
<li><a href="/editor" className="navbar__link">Editor</a></li> </Link>
</li>
<li>
<Link to="/notebook" className="navbar__link">
NoteBook
</Link>
</li>
<li>
<Link to="/assignment" className="navbar__link">
Assignment
</Link>
</li>
<li>
<Link to="/editor" className="navbar__link">
Editor
</Link>
</li>
<li>
<Link to="/login" className="navbar__link">
Login
</Link>
</li>
</ul> </ul>
</nav> </nav>
) );
} };
export default Navbar export default Navbar;

View file

@ -5,11 +5,10 @@ import "./scss/styles.scss";
import Navbar from "./components/Navbar"; import Navbar from "./components/Navbar";
import Hero from "./components/Hero"; import Hero from "./components/Hero";
import Services from "./components/Services"; import Services from "./components/Services";
import Header from "./components/Header";
createRoot(document.getElementById("root")).render( createRoot(document.getElementById("root")).render(
<StrictMode> <StrictMode>
<AppRouter /> <AppRouter />
</StrictMode> </StrictMode>
); );

View file

@ -8,7 +8,7 @@ const LoginPage = () => {
const [type, setType] = useState("signIn"); const [type, setType] = useState("signIn");
useEffect(() => { useEffect(() => {
document.title = "Login / Sign Up"; document.title = "Login / Instructor";
}, []); }, []);
const handleOnClick = (text) => { const handleOnClick = (text) => {
@ -23,7 +23,7 @@ const LoginPage = () => {
return ( return (
<main className="login-page"> <main className="login-page">
<section> <section>
<h2>Sign In/Sign Up</h2> <h2>Student/Instructor</h2>
<div className={containerClass} id="container"> <div className={containerClass} id="container">
<SignUpForm /> <SignUpForm />
<SignInForm /> <SignInForm />
@ -31,26 +31,24 @@ const LoginPage = () => {
<div className="overlay"> <div className="overlay">
<div className="overlay-panel overlay-left"> <div className="overlay-panel overlay-left">
<h1>Welcome Back!</h1> <h1>Welcome Back!</h1>
<p> <p>Please login with your personal info</p>
To keep connected with us please login with your personal info
</p>
<button <button
className="ghost" className="ghost"
id="signIn" id="signIn"
onClick={() => handleOnClick("signIn")} onClick={() => handleOnClick("signIn")}
> >
Sign In Student
</button> </button>
</div> </div>
<div className="overlay-panel overlay-right"> <div className="overlay-panel overlay-right">
<h1>Hello, Friend!</h1> <h1>Hello, Instructor!</h1>
<p>Enter your personal details and start journey with us</p> <p>Please enter your personal details here</p>
<button <button
className="ghost" className="ghost"
id="signUp" id="signUp"
onClick={() => handleOnClick("signUp")} onClick={() => handleOnClick("signUp")}
> >
Sign Up Instructor
</button> </button>
</div> </div>
</div> </div>

View file

@ -31,22 +31,16 @@ function SignInForm() {
return ( return (
<div className="form-container sign-in-container"> <div className="form-container sign-in-container">
<form onSubmit={handleOnSubmit}> <form onSubmit={handleOnSubmit}>
<h1>Sign in</h1> <h1>Student</h1>
<div className="social-container"> {/* <div className="social-container">
<a href="#" className="social">
<i className="fab fa-facebook-f" />
</a>
<a href="#" className="social"> <a href="#" className="social">
<i className="fab fa-google-plus-g" /> <i className="fab fa-google-plus-g" />
</a> </a>
<a href="#" className="social"> </div> */}
<i className="fab fa-linkedin-in" />
</a>
</div>
<span>or use your account</span>
<input <input
type="email" type="email"
placeholder="Email" placeholder="Student Name"
name="email" name="email"
value={state.email} value={state.email}
onChange={handleChange} onChange={handleChange}
@ -58,7 +52,7 @@ function SignInForm() {
value={state.password} value={state.password}
onChange={handleChange} onChange={handleChange}
/> />
<a href="#">Forgot your password?</a>
<button>Sign In</button> <button>Sign In</button>
</form> </form>
</div> </div>

View file

@ -18,7 +18,7 @@ function SignUpForm() {
const { name, email, password } = state; const { name, email, password } = state;
alert( alert(
`You are sign up with name: ${name} email: ${email} and password: ${password}` `You are signed in with name: ${name} email: ${email} and password: ${password}`
); );
for (const key in state) { for (const key in state) {
@ -29,20 +29,18 @@ function SignUpForm() {
} }
}; };
const googleAuth = () => {
window.open("https://byte-camp-auth-service.fly.dev/auth/google", "_self");
};
return ( return (
<div className="form-container sign-up-container"> <div className="form-container sign-up-container">
<form onSubmit={handleOnSubmit}> <form onSubmit={handleOnSubmit}>
<h1>Create Account</h1> <h1>Instructor</h1>
<div className="social-container"> <div className="social-container">
<a href="#" className="social"> <a href="#" className="social" onClick={googleAuth}>
<i className="fab fa-facebook-f" />
</a>
<a href="#" className="social">
<i className="fab fa-google-plus-g" /> <i className="fab fa-google-plus-g" />
</a> </a>
<a href="#" className="social">
<i className="fab fa-linkedin-in" />
</a>
</div> </div>
<span>or use your email for registration</span> <span>or use your email for registration</span>
<input <input
@ -66,7 +64,7 @@ function SignUpForm() {
onChange={handleChange} onChange={handleChange}
placeholder="Password" placeholder="Password"
/> />
<button>Sign Up</button> <button>Sign in</button>
</form> </form>
</div> </div>
); );

View file

@ -11,6 +11,7 @@ import HomePage from "../pages/HomePage";
import LoginPage from "../pages/LoginPage"; import LoginPage from "../pages/LoginPage";
import PageCodeEditor from "../pages/CodeEditor"; import PageCodeEditor from "../pages/CodeEditor";
import PageNotFound from "../pages/PageNotFound"; import PageNotFound from "../pages/PageNotFound";
import AssignmentPage from "../pages/AssignmentPage";
import Hero from "../components/Hero"; import Hero from "../components/Hero";
import Navbar from "../components/Navbar"; import Navbar from "../components/Navbar";
import Services from "../components/Services"; import Services from "../components/Services";
@ -20,16 +21,14 @@ const AppRouter = () => {
return ( return (
<BrowserRouter> <BrowserRouter>
<div className="wrapper"> <div className="wrapper">
{/* <Header /> */}
<Navbar /> <Navbar />
<Routes> <Routes>
<Route <Route
path="/" path="/"
element={ element={
<> <>
<Hero /> <Hero />
<Services /> <Services />
</> </>
} }
/> />
@ -43,7 +42,7 @@ const AppRouter = () => {
/> />
<Route path="login" element={<LoginPage />} /> <Route path="login" element={<LoginPage />} />
<Route <Route
path="editor" path="/editor"
element={ element={
<ProtectedRoute> <ProtectedRoute>
<PageCodeEditor /> <PageCodeEditor />
@ -53,7 +52,7 @@ const AppRouter = () => {
<Route path="*" element={<PageNotFound />} /> <Route path="*" element={<PageNotFound />} />
</Routes> </Routes>
<Footer /> <Footer />
</div> </div>
</BrowserRouter> </BrowserRouter>

View file

@ -1,3 +1,21 @@
// .login-page {
// min-height: 100vh;
// display: flex;
// justify-content: center;
// align-items: center;
// background-image: url("../../../public/images/grid-background.png");
// background-size: cover;
// background-position: center;
// background-repeat: no-repeat;
// background-attachment: fixed;
// section {
// width: 100%;
// max-width: 800px;
// padding: 20px;
// }
// }
.App { .App {
font-family: sans-serif; font-family: sans-serif;
text-align: center; text-align: center;
@ -10,7 +28,12 @@
} }
body { body {
background: #f6f5f7; background: transparent;
background-image: url("../../../public/images/grid-background.jpg");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -27,6 +50,8 @@ h1 {
h2 { h2 {
text-align: center; text-align: center;
color: #fff;
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5);
} }
p { p {
@ -227,8 +252,8 @@ input {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
margin: 0 5px; margin: 0 5px;
height: 40px; height: 60px;
width: 40px; width: 60px;
} }
footer { footer {

View file

@ -0,0 +1,198 @@
// Assignment Page Styling
.assignment-page {
display: flex;
flex-direction: column;
align-items: center;
padding: 2rem;
section {
width: 100%;
max-width: 900px;
}
.assignment-header {
margin-bottom: 2rem;
border-bottom: 1px solid #e0e0e0;
padding-bottom: 1rem;
h2 {
font-size: 3rem;
margin-bottom: 1rem;
color: #ffffff;
}
.due-date {
color: #c6c6c6;
font-size: 1.2rem;
}
}
.assignment-container {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 2rem;
.assignment-info {
margin-bottom: 2rem;
h3 {
font-size: 1.4rem;
margin-bottom: 0.5rem;
color: #333;
}
.files-count {
font-size: 1rem;
margin-bottom: 0.5rem;
}
.submission-note {
font-size: 0.9rem;
color: #666;
}
}
.file-upload-section {
margin-bottom: 2rem;
.upload-buttons {
display: flex;
gap: 1rem;
margin-bottom: 1.5rem;
flex-wrap: wrap;
.file-upload-btn,
.record-audio-btn,
.record-video-btn {
background-color: #f5f5f5;
border: 1px solid #ddd;
border-radius: 4px;
padding: 0.6rem 1rem;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.2s ease;
color: #333;
&:hover {
background-color: #e9e9e9;
}
}
}
.files-list {
background-color: #f9f9f9;
border-radius: 6px;
padding: 1rem;
h4 {
margin-bottom: 0.8rem;
font-size: 1rem;
}
ul {
list-style: none;
padding: 0;
.file-item {
display: flex;
align-items: center;
padding: 0.5rem 0;
border-bottom: 1px solid #eee;
&:last-child {
border-bottom: none;
}
.file-name {
flex-grow: 1;
font-weight: 500;
}
.file-size {
color: #777;
margin: 0 1rem;
font-size: 0.8rem;
}
.remove-file-btn {
background-color: transparent;
border: none;
color: #ff5252;
cursor: pointer;
font-size: 0.8rem;
padding: 0.3rem 0.6rem;
&:hover {
text-decoration: underline;
}
}
}
}
}
}
.comments-section {
margin-bottom: 2rem;
h4 {
margin-bottom: 0.8rem;
font-size: 1rem;
}
textarea {
width: 100%;
border: 1px solid #ddd;
border-radius: 4px;
padding: 0.8rem;
font-family: inherit;
resize: vertical;
&:focus {
outline: none;
border-color: #4a90e2;
}
}
}
.submission-buttons {
display: flex;
gap: 1rem;
.submit-btn,
.cancel-btn {
padding: 0.7rem 1.5rem;
border-radius: 4px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.submit-btn {
background-color: #4a90e2;
color: white;
border: none;
&:hover {
background-color: #3a7bc8;
}
&:disabled {
background-color: #a0c3e8;
cursor: not-allowed;
}
}
.cancel-btn {
background-color: transparent;
border: 1px solid #ddd;
color: #666;
&:hover {
background-color: #f5f5f5;
}
}
}
}
}

View file

@ -13,6 +13,7 @@
@use "./page//home"; @use "./page//home";
@use "./page//login"; @use "./page//login";
@use "./page/code_editor"; @use "./page/code_editor";
@use "./page/assignment";
// Utilities // Utilities
@use "./utilities/utility-classes"; @use "./utilities/utility-classes";