13 changed files with 491 additions and 231 deletions
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
package models |
||||
|
||||
import ( |
||||
"fmt" |
||||
"log" |
||||
"time" |
||||
|
||||
"sponsorahacker/db" |
||||
) |
||||
|
||||
type Goal struct { |
||||
id int |
||||
Name string `form:"item-name" db:"name" binding:"required"` |
||||
FundingAmount float64 `form:"funding-amount" db:"funding_amount" binding:"required,numeric"` |
||||
Description string `form:"item-description" db:"description" binding:"required"` |
||||
LearnMoreURL string `form:"item-url" db:"learn_more_url"` // Optional field
|
||||
CreatedAt time.Time `db:"created_at"` |
||||
UpdatedAt time.Time `db:"updated_at"` |
||||
CreatedBy int `db:"created_by"` |
||||
} |
||||
|
||||
func (g *Goal) CreateGoal() error { |
||||
dbClient, err := db.NewDbClient() |
||||
|
||||
if err != nil { |
||||
log.Fatalf("Could not connect to database: %v", err) |
||||
return err |
||||
} |
||||
_, err = dbClient.Exec(`INSERT INTO goals (name, description, learn_more_url, funding_amount, created_by, created_at, updated_at) |
||||
VALUES (?, ?, ?, ?, ?, ?, ?);`, g.Name, g.Description, g.LearnMoreURL, g.FundingAmount, g.CreatedBy, g.CreatedAt, g.UpdatedAt) |
||||
|
||||
if err != nil { |
||||
log.Fatalf("Could not create goal: %v", err) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func GetGoals(user int) ([]Goal, error) { |
||||
var goals []Goal |
||||
|
||||
dbClient, err := db.NewDbClient() |
||||
|
||||
if err != nil { |
||||
log.Fatalf("Could not connect to database: %v", err) |
||||
} |
||||
|
||||
result, err := dbClient.Query(`SELECT name, description, learn_more_url, funding_amount, created_by, created_at, updated_at FROM goals where created_by = ?`, user) |
||||
|
||||
if err != nil { |
||||
log.Fatalf("Could not get goals: %v", err) |
||||
} |
||||
for result.Next() { |
||||
var goal Goal |
||||
err = result.StructScan(&goal) |
||||
|
||||
fmt.Println(goal.Name) |
||||
|
||||
if err != nil { |
||||
log.Fatalf("Could not read goal: %v", err) |
||||
return nil, err |
||||
} |
||||
goals = append(goals, goal) |
||||
} |
||||
|
||||
return goals, nil |
||||
} |
||||
|
||||
func GetGoal(id int) (*Goal, error) { |
||||
dbClient, err := db.NewDbClient() |
||||
result, err := dbClient.Query(`SELECT name, description, learn_more_url, funding_amount, created_by, created_at, updated_at FROM goals where id = ?`, id) |
||||
|
||||
if err != nil { |
||||
log.Fatalf("Could not read goal: %v", err) |
||||
return nil, err |
||||
} |
||||
|
||||
var goal Goal |
||||
err = result.StructScan(&goal) |
||||
|
||||
return &goal, nil |
||||
} |
||||
@ -0,0 +1,148 @@
@@ -0,0 +1,148 @@
|
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
<link rel="stylesheet" type="text/css" href="/assets/css/style.css" /> |
||||
<title>Goal Page</title> |
||||
<style> |
||||
/* General Styles */ |
||||
body { |
||||
font-family: Arial, sans-serif; |
||||
background-color: #F4F1EB; /* Light cream background */ |
||||
margin: 0; |
||||
padding: 0; |
||||
color: #2B2D42; /* Dark gray text */ |
||||
} |
||||
|
||||
header { |
||||
background-color: #457B9D; /* Muted blue header */ |
||||
color: #FFFFFF; |
||||
padding: 20px; |
||||
text-align: center; |
||||
} |
||||
|
||||
main { |
||||
max-width: 800px; |
||||
margin: 20px auto; |
||||
padding: 20px; |
||||
background-color: #FFFFFF; /* White card */ |
||||
border: 1px solid #A3C1AD; /* Muted green border */ |
||||
border-radius: 10px; |
||||
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); |
||||
} |
||||
|
||||
h1, h2 { |
||||
color: #457B9D; /* Muted blue text */ |
||||
} |
||||
|
||||
h1 { |
||||
font-size: 2rem; |
||||
} |
||||
|
||||
h2 { |
||||
font-size: 1.5rem; |
||||
margin-top: 20px; |
||||
} |
||||
|
||||
p { |
||||
margin: 10px 0; |
||||
line-height: 1.6; |
||||
} |
||||
|
||||
.goal-details { |
||||
margin-bottom: 20px; |
||||
} |
||||
|
||||
.goal-progress { |
||||
margin: 20px 0; |
||||
} |
||||
|
||||
.progress-bar { |
||||
background-color: #A3C1AD; /* Muted green */ |
||||
height: 20px; |
||||
width: 70%; /* Example progress, replace dynamically */ |
||||
max-width: 100%; |
||||
border-radius: 5px; |
||||
} |
||||
|
||||
.progress-container { |
||||
background-color: #F4F1EB; /* Light cream */ |
||||
border: 1px solid #A3C1AD; /* Muted green */ |
||||
border-radius: 5px; |
||||
height: 20px; |
||||
overflow: hidden; |
||||
margin-bottom: 10px; |
||||
} |
||||
|
||||
.actions { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
gap: 10px; |
||||
margin-top: 20px; |
||||
} |
||||
|
||||
.actions button { |
||||
background-color: #A3C1AD; /* Muted green button */ |
||||
color: #FFFFFF; |
||||
border: none; |
||||
padding: 10px 20px; |
||||
border-radius: 5px; |
||||
font-size: 1rem; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.actions button:hover { |
||||
background-color: #87B09C; /* Slightly darker muted green */ |
||||
} |
||||
|
||||
.link { |
||||
text-align: center; |
||||
margin-top: 20px; |
||||
} |
||||
|
||||
.link a { |
||||
color: #457B9D; /* Muted blue */ |
||||
text-decoration: none; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.link a:hover { |
||||
text-decoration: underline; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
{{template "pageheader" . }} |
||||
|
||||
<main> |
||||
<!-- Goal Details Section --> |
||||
<section class="goal-details"> |
||||
<h2>Goal: Learn Full-Stack Development</h2> |
||||
<p>Description: A comprehensive course to master full-stack web development. This goal includes learning front-end and back-end technologies to build robust applications.</p> |
||||
<p>Funding Needed: <strong>$500</strong></p> |
||||
<p>Funding Received: <strong>$350</strong></p> |
||||
</section> |
||||
|
||||
<!-- Progress Bar Section --> |
||||
<section class="goal-progress"> |
||||
<h2>Funding Progress</h2> |
||||
<div class="progress-container"> |
||||
<div class="progress-bar"></div> |
||||
</div> |
||||
<p>70% funded</p> |
||||
</section> |
||||
|
||||
<!-- Actions Section --> |
||||
<section class="actions"> |
||||
<button>Donate</button> |
||||
<button>Share</button> |
||||
</section> |
||||
|
||||
<!-- External Link Section --> |
||||
<div class="link"> |
||||
<a href="#">Learn more about this goal</a> |
||||
</div> |
||||
</main> |
||||
</body> |
||||
</html> |
||||
@ -1,14 +1,17 @@
@@ -1,14 +1,17 @@
|
||||
{{define "pageheader"}} |
||||
<div class="header"> |
||||
<img src="assets/images/logo.jpg" class="logo"/> |
||||
<h1 class="title"> |
||||
Sponsor A Hacker |
||||
</h1> |
||||
<img src="/assets/images/logo.jpg" class="logo"/> |
||||
|
||||
{{if eq .isLoggedIn false}} |
||||
<h1 class="title"> |
||||
<a href="/" class="title-link">Sponsor A Hacker</a> |
||||
</h1> |
||||
<a href="/login" class="login-banner-link">Login</a> |
||||
{{ else }} |
||||
<a href="auth/logout/twitch" class="login-banner-link">Logout</a> |
||||
<h1 class="title"> |
||||
<a href="/welcome" class="title-link">Sponsor A Hacker</a> |
||||
</h1> |
||||
<a href="/auth/logout/twitch" class="login-banner-link">Logout</a> |
||||
{{ end }} |
||||
|
||||
</div> |
||||
|
||||
@ -0,0 +1,116 @@
@@ -0,0 +1,116 @@
|
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
<title>Submit Hackathon Project</title> |
||||
<style> |
||||
body { |
||||
font-family: Arial, sans-serif; |
||||
background-color: #F4F1EB; /* Light cream background */ |
||||
color: #2B2D42; /* Dark gray text */ |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
height: 100vh; |
||||
margin: 0; |
||||
} |
||||
|
||||
.form-container { |
||||
background-color: #FFFFFF; /* White form background */ |
||||
border: 2px solid #457B9D; /* Muted blue border */ |
||||
border-radius: 10px; |
||||
padding: 20px; |
||||
width: 400px; |
||||
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); |
||||
} |
||||
|
||||
.form-container h2 { |
||||
text-align: center; |
||||
color: #457B9D; /* Muted blue heading */ |
||||
margin-bottom: 20px; |
||||
} |
||||
|
||||
.form-group { |
||||
margin-bottom: 15px; |
||||
} |
||||
|
||||
.form-group label { |
||||
display: block; |
||||
font-weight: bold; |
||||
margin-bottom: 5px; |
||||
} |
||||
|
||||
.form-group input[type="text"], |
||||
.form-group textarea, |
||||
.form-group input[type="file"] { |
||||
width: 100%; |
||||
padding: 10px; |
||||
font-size: 1rem; |
||||
border: 1px solid #A3C1AD; /* Muted green border */ |
||||
border-radius: 5px; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.form-group textarea { |
||||
height: 100px; |
||||
resize: vertical; |
||||
} |
||||
|
||||
.form-group input[type="file"] { |
||||
padding: 5px; |
||||
} |
||||
|
||||
.form-group input[type="file"]::file-selector-button { |
||||
background-color: #457B9D; /* Muted blue button */ |
||||
color: #FFFFFF; /* White text */ |
||||
border: none; |
||||
border-radius: 5px; |
||||
padding: 5px 10px; |
||||
cursor: pointer; |
||||
font-size: 0.9rem; |
||||
} |
||||
|
||||
.form-group input[type="file"]::file-selector-button:hover { |
||||
background-color: #356081; /* Slightly darker blue */ |
||||
} |
||||
|
||||
.submit-btn { |
||||
display: block; |
||||
width: 100%; |
||||
background-color: #A3C1AD; /* Muted green button */ |
||||
color: #FFFFFF; |
||||
border: none; |
||||
border-radius: 5px; |
||||
padding: 10px; |
||||
font-size: 1rem; |
||||
cursor: pointer; |
||||
text-align: center; |
||||
} |
||||
|
||||
.submit-btn:hover { |
||||
background-color: #87B09C; /* Slightly darker green */ |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<div class="form-container"> |
||||
<h2>Submit Your Hack</h2> |
||||
<form action="/submit-hack" method="POST" enctype="multipart/form-data"> |
||||
<div class="form-group"> |
||||
<label for="hack-name">Hack Name</label> |
||||
<input type="text" id="hack-name" name="hack-name" placeholder="Enter your hack name" required> |
||||
</div> |
||||
<div class="form-group"> |
||||
<label for="description">Description</label> |
||||
<textarea id="description" name="description" placeholder="Describe your hack" required></textarea> |
||||
</div> |
||||
<div class="form-group"> |
||||
<label for="docker-file">Upload Docker Image</label> |
||||
<input type="file" id="docker-file" name="docker-file" accept=".tar,.tar.gz" required> |
||||
</div> |
||||
<button type="submit" class="submit-btn">Submit Hack</button> |
||||
</form> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
Loading…
Reference in new issue