web: finishing supabase auth

This commit is contained in:
ryan 2025-02-16 20:24:40 +08:00
parent 3b8620cb61
commit 90ff7e14ee
22 changed files with 407 additions and 130 deletions

5
web/.firebaserc Normal file
View file

@ -0,0 +1,5 @@
{
"projects": {
"default": "sweet-starry-lil-rabbits"
}
}

69
web/.gitignore vendored Normal file
View file

@ -0,0 +1,69 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
firebase-debug.log*
firebase-debug.*.log*
# Firebase cache
.firebase/
# Firebase config
# Uncomment this if you'd like others to create their own Firebase project.
# For a team working on the same Firebase project(s), it is recommended to leave
# it commented so all members can deploy to the same project(s) in .firebaserc.
# .firebaserc
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# dataconnect generated files
.dataconnect

10
web/firebase.json Normal file
View file

@ -0,0 +1,10 @@
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}

View file

@ -1,104 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Solace Of Service</title>
<link rel="stylesheet" href="main.css" />
<link rel="icon" type="image/x-icon" href="./img/SOS_Logo_WBG.png" />
</head>
<body class="h-screen w-screen main-colour">
<header class="flex w-full h-20 secondary-colour fixed top-0 left-0 right-0">
<img src="./img/SOS_Logo_WBG.png" alt="product logo" class="p-1 ml-10" />
<nav class="w-full flex justify-around">
<a href="./index.html" class="px-4 text-justify h-fit w-fit self-center"
><h1>Home</h1></a
>
<a href="./about.html" class="px-4 text-justify h-fit w-fit self-center"
><h1>About SSLR</h1></a
>
<a href="#" class="px-4 text-justify h-fit w-fit self-center"><h1>Profile</h1></a>
</nav>
</header>
<div class="h-20"></div>
<dialog
id="signInDialog"
class="section-colour w-[40vw] absolute top-[50%] left-[50%] translate-[-50%] backdrop:opacity-75 backdrop:bg-zinc800"
>
<b>Login</b>
<form>
<label for="email">Email:</label><br />
<input
type="email"
name="email"
id="email"
class="cursor-text border-2 w-3/4 rounded-md bg-slate-200"
/><br />
<label for="password">Password:</label><br />
<input
type="password"
name="password"
id="password"
class="cursor-text border-2 w-3/4 rounded-md bg-slate-200"
/><br />
<button
autofocus
type="submit"
id="SignInSubmit"
class="cursor-pointer px-1 border-2 my-2 main-colour border-black rounded-md hover:bg-slate-200"
>
SignIn</button
><br />
<button
id="signinToSignup"
type="button"
class="cursor-pointer px-1 my-2 rounded-md"
>
Dont have an account? Click here to create one.
</button>
</form>
</dialog>
<dialog
open
id="signDialog"
class="section-colour w-[40vw] absolute top-[50%] left-[50%] translate-[-50%] backdrop:opacity-75 backdrop:bg-zinc800"
>
<b>Login</b>
<form>
<label for="email">Email:</label><br />
<input
type="email"
name="email"
id="email"
class="cursor-text border-2 w-3/4 rounded-md bg-slate-200"
/><br />
<label for="password">Password:</label><br />
<input
type="password"
name="password"
id="password"
class="cursor-text border-2 w-3/4 rounded-md bg-slate-200"
/><br />
<button
autofocus
type="submit"
id="SignInSubmit"
class="cursor-pointer px-1 border-2 my-2 main-colour border-black rounded-md hover:bg-slate-200"
>
SignIn</button
><br />
<button
id="signinToSignup"
type="button"
class="cursor-pointer px-1 my-2 rounded-md"
>
Dont have an account? Click here to create one.
</button>
</form>
</dialog>
<footer class="secondary-colour h-40">
<h2></h2>
</footer>
<script type="module" src="./profile.js"></script>
</body>
</html>

View file

@ -1,21 +0,0 @@
const signInDialog = document.getElementById("signInDialog");
const signUpDialog = document.getElementById("signUpDialog");
document.addEventListener("DOMContentLoaded", (event) => {});
function ShowSignIn() {
// signUpDialog.close();
signInDialog.showModal();
console.log("sign in showed");
}
function ShowSignUp() {
signInDialog.close()
signUpDialog.showModal()
console.log("sign up showed")
}

33
web/public/404.html Normal file
View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page Not Found</title>
<style media="screen">
body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; }
#message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px 16px; border-radius: 3px; }
#message h3 { color: #888; font-weight: normal; font-size: 16px; margin: 16px 0 12px; }
#message h2 { color: #ffa100; font-weight: bold; font-size: 16px; margin: 0 0 8px; }
#message h1 { font-size: 22px; font-weight: 300; color: rgba(0,0,0,0.6); margin: 0 0 16px;}
#message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; }
#message a { display: block; text-align: center; background: #039be5; text-transform: uppercase; text-decoration: none; color: white; padding: 16px; border-radius: 4px; }
#message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); }
#load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; }
@media (max-width: 600px) {
body, #message { margin-top: 0; background: white; box-shadow: none; }
body { border-top: 16px solid #ffa100; }
}
</style>
</head>
<body>
<div id="message">
<h2>404</h2>
<h1>Page Not Found</h1>
<p>The specified file was not found on this website. Please check the URL for mistakes and try again.</p>
<h3>Why am I seeing this?</h3>
<p>This page was generated by the Firebase Command-Line Interface. To modify it, edit the <code>404.html</code> file in your project's configured <code>public</code> directory.</p>
</div>
</body>
</html>

View file

@ -1,7 +1,7 @@
/*! tailwindcss v4.0.0 | MIT License | https://tailwindcss.com */ /*! tailwindcss v4.0.6 | MIT License | https://tailwindcss.com */
@layer theme, base, components, utilities; @layer theme, base, components, utilities;
@layer theme { @layer theme {
:root { :root, :host {
--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
@ -551,6 +551,9 @@
.ml-10 { .ml-10 {
margin-left: calc(var(--spacing) * 10); margin-left: calc(var(--spacing) * 10);
} }
.block {
display: block;
}
.flex { .flex {
display: flex; display: flex;
} }
@ -671,6 +674,9 @@
.px-4 { .px-4 {
padding-inline: calc(var(--spacing) * 4); padding-inline: calc(var(--spacing) * 4);
} }
.px-5 {
padding-inline: calc(var(--spacing) * 5);
}
.px-\[15vw\] { .px-\[15vw\] {
padding-inline: 15vw; padding-inline: 15vw;
} }
@ -710,9 +716,49 @@
--tw-font-weight: var(--font-weight-bold); --tw-font-weight: var(--font-weight-bold);
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
} }
.backdrop\:opacity-75 { .uppercase {
text-transform: uppercase;
}
.file\:mr-4 {
&::file-selector-button {
margin-right: calc(var(--spacing) * 4);
}
}
.file\:rounded-full {
&::file-selector-button {
border-radius: calc(infinity * 1px);
}
}
.file\:border {
&::file-selector-button {
border-style: var(--tw-border-style);
border-width: 1px;
}
}
.file\:border-black {
&::file-selector-button {
border-color: var(--color-black);
}
}
.file\:bg-\[\#c6cdd9\] {
&::file-selector-button {
background-color: #c6cdd9;
}
}
.file\:px-2 {
&::file-selector-button {
padding-inline: calc(var(--spacing) * 2);
}
}
.file\:font-semibold {
&::file-selector-button {
--tw-font-weight: var(--font-weight-semibold);
font-weight: var(--font-weight-semibold);
}
}
.backdrop\:opacity-20 {
&::backdrop { &::backdrop {
opacity: 75%; opacity: 20%;
} }
} }
.hover\:bg-slate-200 { .hover\:bg-slate-200 {

View file

@ -1,5 +1,5 @@
{ {
"name": "IP3", "name": "web",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {

121
web/public/profile.html Normal file
View file

@ -0,0 +1,121 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Solace Of Service</title>
<link rel="stylesheet" href="main.css" />
<link rel="icon" type="image/x-icon" href="./img/SOS_Logo_WBG.png" />
<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
</head>
<body class="h-screen w-screen main-colour">
<header class="flex w-full h-20 secondary-colour fixed top-0 left-0 right-0">
<img src="./img/SOS_Logo_WBG.png" alt="product logo" class="p-1 ml-10" />
<nav class="w-full flex justify-around">
<a href="./index.html" class="px-4 text-justify h-fit w-fit self-center"
><h1>Home</h1></a
>
<a href="./about.html" class="px-4 text-justify h-fit w-fit self-center"
><h1>About SSLR</h1></a
>
<a href="#" class="px-4 text-justify h-fit w-fit self-center"><h1>Profile</h1></a>
</nav>
</header>
<div class="h-20"></div>
<dialog
id="signInDialog"
class="section-colour px-5 w-[40vw] absolute top-[50%] left-[50%] translate-[-50%] backdrop:opacity-20 backdrop:bg-zinc800"
>
<b>Login</b>
<form>
<label for="email">Email:</label><br />
<input
name="email"
id="emailSignIn"
class="cursor-text border-2 w-3/4 rounded-md bg-slate-200"
/><br />
<label for="password">Password:</label><br />
<input
name="password"
id="passwordSignIn"
class="cursor-text border-2 w-3/4 rounded-md bg-slate-200"
/><br />
<input
type="button"
id="SignInSubmit"
value="Sign In"
class="cursor-pointer px-1 border-2 my-2 main-colour border-black rounded-md hover:bg-slate-200"
/><br />
<button
id="signinToSignup"
type="button"
class="cursor-pointer px-1 my-2 rounded-md"
>
Dont have an account? Click here to create one.
</button>
</form>
</dialog>
<dialog
id="signUpDialog"
class="section-colour px-5 w-[40vw] absolute top-[50%] left-[50%] translate-[-50%] backdrop:opacity-20 backdrop:bg-zinc800"
>
<b>Sign Up</b>
<form>
<label for="username">Username:</label><br />
<input
type="text"
id="usernameSignUp"
name="username"
class="cursor-text border-2 w-3/4 rounded-md bg-slate-200"
/><br />
<label for="email">Email:</label><br />
<input
name="email"
id="emailSignUp"
class="cursor-text border-2 w-3/4 rounded-md bg-slate-200"
/><br />
<label for="password">Password:</label><br />
<input
name="password"
id="passwordSignUp"
class="cursor-text border-2 w-3/4 rounded-md bg-slate-200"
/><br />
<label for="profile"> Profile Picture</label><br />
<input
type="file"
name="profile"
id="profileSignUp"
accept="image/*"
class="file:rounded-full file:border file:border-black file:px-2 file:mr-4 file:font-semibold file:bg-[#c6cdd9]"
/><br />
<input
type="button"
id="SignUpSubmit"
value="Sign Up"
class="cursor-pointer px-1 border-2 my-2 main-colour border-black rounded-md hover:bg-slate-200"
/>
<br />
<button
id="signUpToSignIn"
type="button"
class="cursor-pointer px-1 my-2 rounded-md"
>
Do you got an account? Click here to Login
</button>
</form>
</dialog>
<section class="h-fit w-full py-10 px-[15vw]">
<b>Profile</b>
<img src="" class="" alt="Profile picture" />
<h1><b>Name:</b></h1>
<h1><b>Score:</b></h1>
<h1><b>Days Played:</b></h1>
<h1><b>Customers Helped Correct:</b></h1>
<h1><b>Customers Helped Wrongly:</b></h1>
<h1><b>Accuracy:</b></h1>
</section>
<script src="./profile.js"></script>
</body>
</html>

118
web/public/profile.js Normal file
View file

@ -0,0 +1,118 @@
const { createClient } = supabase;
const supabaseUrl = "https://fchobpauqasfebohuuam.supabase.co";
const supabaseAnonKey =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZjaG9icGF1cWFzZmVib2h1dWFtIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzczNTYyNTUsImV4cCI6MjA1MjkzMjI1NX0.LkwCnzjtf8CPLrm6OONkjyjxZW8jE05V_spbOEeAXEM";
const Supabase = createClient(supabaseUrl, supabaseAnonKey);
const signInDialog = document.getElementById("signInDialog");
const signUpDialog = document.getElementById("signUpDialog");
var uid = "";
document.addEventListener("DOMContentLoaded", (event) => {
Start();
});
document.getElementById("SignInSubmit").addEventListener("click", (e) => {
e.preventDefault;
var email = document.getElementById("emailSignIn").value;
var password = document.getElementById("passwordSignIn").value;
SignIn(email, password);
});
document.getElementById("SignUpSubmit").addEventListener("click", (e) => {
e.preventDefault;
var email = document.getElementById("emailSignUp").value;
var password = document.getElementById("passwordSignUp").value;
var username = document.getElementById("usernameSignUp").value;
var fileInput = document.getElementById("profileSignUp");
const file = fileInput.files[0];
SignUp(email, password, username, file);
});
document.getElementById("signUpToSignIn").addEventListener("click", () => {
ShowSignIn();
});
document.getElementById("signinToSignup").addEventListener("click", () => {
ShowSignUp();
});
function ShowSignIn() {
signUpDialog.close();
signInDialog.showModal();
console.log("sign in showed");
}
function ShowSignUp() {
signInDialog.close();
signUpDialog.showModal();
console.log("sign up showed");
}
function closeDialog() {
signInDialog.close();
signUpDialog.close();
}
async function Start() {
const { data } = await Supabase.auth.getSession();
console.log(data);
if (data.session == null || data.session == "") {
uid = "";
ShowSignUp();
} else {
uid = data.session.user.id;
}
}
async function SignIn(email, password) {
console.log(email, password);
const { data: auth, error: authError } = await Supabase.auth.signInWithPassword({
email: email,
password: password,
});
if (authError) {
console.error("Error signing in:", authError.message);
return;
}
console.log("User signed in:", auth);
uid = auth.user.id;
const { data, error } = await Supabase.from("users").select();
console.log(data);
if (error) {
console.error("Error getting data:", error.message);
return;
}
closeDialog();
}
async function SignUp(email, password, username, file) {
console.log(email, password);
const { data, error: authError } = await Supabase.auth.signUp({
email: email,
password: password,
});
uid = data.user.id;
if (file.size > 1e7) {
console.error("file too fat");
}
const fileName = `${Date.now()}-${file.name}`;
const { storeData, storeError } = await Supabase.storage
.from("Avatar") // Replace 'images' with your bucket name
.upload(fileName, file);
if (storeError) {
console.error("Upload failed:", storeError.message);
return;
}
const publicUrlData = Supabase.storage.from("Avatar").getPublicUrl(fileName);
const publicUrl = publicUrlData.data.publicUrl;
console.log("Public URL:", publicUrl);
const { error } = await Supabase.from("users").insert({
uid: uid,
displayName: username,
profilePictureUrl: publicUrl,
});
}