-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: sorted completed quests and created daily and main quest routes #1
(#54) * add sorting for completed * Create quest.go To store Quest Structs * Create Quests.go * Update routes.go * Update routes.go * Update and rename Quests.go to quests.go * Update quest.go * Delete quest.go * Update quests.go Updates to quests route * Update quests.go Changed route name to follow other routes pattern. * Update quests.go * Update Quests.js to consume mainQuests and dailyQuests routes * Update Quests.js * Display local quests for now --------- Co-authored-by: Otaiki1 <[email protected]> Co-authored-by: Brandon Roberts <[email protected]> Co-authored-by: Brandon R <[email protected]>
- Loading branch information
1 parent
c8c6edc
commit 3fa4ac8
Showing
3 changed files
with
169 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package routes | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"log" | ||
"net/http" | ||
|
||
"github.com/keep-starknet-strange/art-peace/backend/core" | ||
) | ||
|
||
// the Quest struct will represent the structure for both Daily and Main Quests data | ||
type Quest struct { | ||
Key int `json:"key"` | ||
Name string `json:"name"` | ||
Description string `json:"description"` | ||
Reward int `json:"reward"` | ||
DayIndex int `json:"dayIndex,omitempty"` // Only for daily quests | ||
} | ||
|
||
func InitQuestsRoutes() { | ||
http.HandleFunc("/getDailyQuests", GetDailyQuests) | ||
http.HandleFunc("/getMainQuests", GetMainQuests) | ||
} | ||
|
||
// Query dailyQuests | ||
func GetDailyQuests(w http.ResponseWriter, r *http.Request) { | ||
query := `SELECT key, name, description, reward, dayIndex FROM DailyQuests ORDER BY dayIndex ASC` | ||
handleQuestQuery(w, r, query) | ||
} | ||
|
||
// Query mainQuest | ||
func GetMainQuests(w http.ResponseWriter, r *http.Request) { | ||
query := `SELECT key, name, description, reward FROM MainQuests` | ||
handleQuestQuery(w, r, query) | ||
} | ||
|
||
func handleQuestQuery(w http.ResponseWriter, r *http.Request, query string) { | ||
var quests []Quest | ||
rows, err := core.ArtPeaceBackend.Databases.Postgres.Query(context.Background(), query) | ||
if err != nil { | ||
http.Error(w, "Database query failed: "+err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
defer rows.Close() | ||
|
||
for rows.Next() { | ||
var q Quest | ||
if err := rows.Scan(&q.Key, &q.Name, &q.Description, &q.Reward, &q.DayIndex); err != nil { | ||
log.Printf("Error scanning row: %v", err) | ||
continue // Log and continue to process other rows | ||
} | ||
quests = append(quests, q) | ||
} | ||
if err := rows.Err(); err != nil { | ||
log.Printf("Error during rows iteration: %v", err) | ||
http.Error(w, "Error processing data: "+err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
setupCORS(&w, r) | ||
w.Header().Set("Content-Type", "application/json") | ||
if err := json.NewEncoder(w).Encode(quests); err != nil { | ||
http.Error(w, "Error encoding response: "+err.Error(), http.StatusInternalServerError) | ||
} | ||
} | ||
|
||
// CORS setup | ||
func setupCORS(w *http.ResponseWriter, r *http.Request) { | ||
(*w).Header().Set("Access-Control-Allow-Origin", "*") | ||
if r.Method == "OPTIONS" { | ||
(*w).Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") | ||
(*w).Header().Set("Access-Control-Allow-Headers", "Content-Type") | ||
(*w).WriteHeader(http.StatusOK) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,74 +1,142 @@ | ||
import React from 'react' | ||
import './Quests.css'; | ||
import BasicTab from '../BasicTab.js'; | ||
import QuestItem from './QuestItem.js'; | ||
import React, { useState, useEffect } from "react"; | ||
import "./Quests.css"; | ||
import BasicTab from "../BasicTab.js"; | ||
import QuestItem from "./QuestItem.js"; | ||
|
||
const Quests = props => { | ||
const Quests = (props) => { | ||
const [dailyQuests, setDailyQuests] = useState([]); | ||
const [mainQuests, setMainQuests] = useState([]); | ||
|
||
useEffect(() => { | ||
const fetchQuests = async () => { | ||
try { | ||
// Fetching daily quests from backend | ||
const dailyResponse = await fetch('http://localhost:8080/getDailyQuests'); | ||
const dailyData = await dailyResponse.json(); | ||
setDailyQuests(dailyData); | ||
|
||
// Fetching main quests from backend | ||
const mainResponse = await fetch('http://localhost:8080/getMainQuests'); | ||
const mainData = await mainResponse.json(); | ||
setMainQuests(mainData); | ||
} catch (error) { | ||
console.error('Failed to fetch quests', error); | ||
} | ||
}; | ||
|
||
fetchQuests(); | ||
}, []); | ||
// TODO: Main quests should be scrollable | ||
// TODO: Main quests should be moved to the bottom on complete | ||
// TODO: Pull quests from backend | ||
// TODO: Links in descriptions | ||
const dailyQuests = [ | ||
|
||
|
||
|
||
const localDailyQuests = [ | ||
{ | ||
title: "Place 10 pixels", | ||
description: "Add 10 pixels on the canvas", | ||
reward: "3", | ||
status: "completed" | ||
status: "completed", | ||
}, | ||
{ | ||
title: "Build a template", | ||
description: "Create a template for the community to use", | ||
reward: "3", | ||
status: "claim" | ||
status: "claim", | ||
}, | ||
{ | ||
title: "Deploy a Memecoin", | ||
description: "Create an Unruggable memecoin", | ||
reward: "10", | ||
status: "completed" | ||
} | ||
] | ||
status: "completed", | ||
}, | ||
]; | ||
|
||
const mainQuests = [ | ||
const localMainQuests = [ | ||
{ | ||
title: "Tweet #art/peace", | ||
description: "Tweet about art/peace using the hashtag & addr", | ||
reward: "10", | ||
status: "incomplete" | ||
status: "incomplete", | ||
}, | ||
{ | ||
title: "Place 100 pixels", | ||
description: "Add 100 pixels on the canvas", | ||
reward: "10", | ||
status: "completed" | ||
status: "completed", | ||
}, | ||
{ | ||
title: "Mint an art/peace NFT", | ||
description: "Mint an NFT using the art/peace theme", | ||
reward: "5", | ||
status: "incomplete" | ||
status: "incomplete", | ||
}, | ||
]; | ||
|
||
const sortByCompleted = (arr) => { | ||
if (!arr) return []; | ||
const newArray = []; | ||
for (let i = 0; i < arr.length; i++) { | ||
if (arr[i].status == "completed") { | ||
newArray.push(arr[i]); | ||
} else { | ||
newArray.unshift(arr[i]); | ||
} | ||
} | ||
] | ||
return newArray; | ||
}; | ||
|
||
// TODO: Icons for each tab? | ||
return ( | ||
<BasicTab title="Quests"> | ||
<div style={{height: '70vh', overflowY: 'scroll'}}> | ||
<div style={{display: 'flex', alignItems: 'center'}}> | ||
<div style={{ height: "70vh", overflowY: "scroll" }}> | ||
<div style={{ display: "flex", alignItems: "center" }}> | ||
<h2 className="Quests__item__header">Dailys</h2> | ||
<p style={{fontSize: "1rem", marginLeft: "1rem"}}>{props.timeLeftInDay}</p> | ||
</div> | ||
{dailyQuests.map((quest, index) => ( | ||
<QuestItem key={index} title={quest.title} description={quest.description} reward={quest.reward} status={quest.status} /> | ||
{sortByCompleted(dailyQuests).map((quest, index) => ( | ||
<QuestItem | ||
key={index} | ||
title={quest.title} | ||
description={quest.description} | ||
reward={quest.reward} | ||
status={quest.status} | ||
/> | ||
))} | ||
|
||
{sortByCompleted(localDailyQuests).map((quest, index) => ( | ||
<QuestItem | ||
key={index} | ||
title={quest.title} | ||
description={quest.description} | ||
reward={quest.reward} | ||
status={quest.status} | ||
/> | ||
))} | ||
|
||
<h2 className="Quests__item__header">Main</h2> | ||
{mainQuests.map((quest, index) => ( | ||
<QuestItem key={index} title={quest.title} description={quest.description} reward={quest.reward} status={quest.status} /> | ||
{sortByCompleted(mainQuests).map((quest, index) => ( | ||
<QuestItem | ||
key={index} | ||
title={quest.title} | ||
description={quest.description} | ||
reward={quest.reward} | ||
status={quest.status} | ||
/> | ||
))} | ||
{sortByCompleted(localMainQuests).map((quest, index) => ( | ||
<QuestItem | ||
key={index} | ||
title={quest.title} | ||
description={quest.description} | ||
reward={quest.reward} | ||
status={quest.status} | ||
/> | ||
))} | ||
</div> | ||
</BasicTab> | ||
); | ||
} | ||
}; | ||
|
||
export default Quests; |