diff --git a/.DS_Store b/.DS_Store index 5dd7a97d..353a86c2 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 8d702cff..3a3f68a4 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,8 @@ yarn-error.log* # local env files .env*.local +.env +/.env # vercel .vercel @@ -36,3 +38,4 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts +TODOs.md diff --git a/components/Data/AccountAvatar.tsx b/components/Data/AccountAvatar.tsx index a2cd6f63..8c5b2ca7 100644 --- a/components/Data/AccountAvatar.tsx +++ b/components/Data/AccountAvatar.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from "react"; import { useSupabaseClient } from "@supabase/auth-helpers-react"; import { Database } from "../../utils/database.types"; + type Profiles = Database['public']['Tables']['profiles']['Row'] export default function AccountAvatar ({ diff --git a/components/Data/OffchainAccount.tsx b/components/Data/OffchainAccount.tsx index 0f2dae19..99eb02a0 100644 --- a/components/Data/OffchainAccount.tsx +++ b/components/Data/OffchainAccount.tsx @@ -1,9 +1,16 @@ -import { useState, useEffect } from "react"; +import React, { useState, createRef, useEffect } from "react"; import { useUser, useSupabaseClient, Session } from "@supabase/auth-helpers-react"; import { Database } from '../../utils/database.types'; import AccountAvatar from "./AccountAvatar"; +import { imagesCdnAddress } from "../../constants/cdn"; +import { v4 as uuidv4 } from 'uuid'; +import Link from "next/link"; +import { Container, Form, Button, Row, Col, Card } from "react-bootstrap"; +import PlanetEditor from "../../pages/generator/planet-editor"; +import { useScreenshot } from "use-react-screenshot"; type Profiles = Database['public']['Tables']['profiles']['Row']; +type Planets = Database['public']['Tables']['planets']['Row']; export default function OffchainAccount({ session }: { session: Session}) { const supabase = useSupabaseClient(); @@ -13,9 +20,21 @@ export default function OffchainAccount({ session }: { session: Session}) { const [website, setWebsite] = useState(null); // I believe this is the email field const [avatar_url, setAvatarUrl] = useState(null); const [address, setAddress] = useState(null); // This should be set by the handler eventually (connected address). + const [images, setImages] = useState([]); + + // User planet + const [userIdForPlanet, setUserIdForPlanet] = useState(null); + const [planetGeneratorImage, setPlanetGeneratorImage] = useState(null); + + const ref = createRef(); + let width = '100%' + const [image, takeScreenShot] = useScreenshot(); + + const getImage = () => takeScreenShot(ref.current); useEffect(() => { getProfile(); + console.log(user.id) }, [session]); async function getProfile() { @@ -79,6 +98,141 @@ export default function OffchainAccount({ session }: { session: Session}) { } } + // Gallery components + // Retrieving gallery data for user + async function getImages() { + const { data, error } = await supabase + .storage + .from('images') + .list(user?.id + '/', { + limit: 100, // Get 100 images from this dir + offset: 0, + sortBy: { + column: 'name', + order: 'asc' + } + }); + + if ( data !== null ) { + setImages(data); + } else { + alert('Error loading images'); + console.log(error); + } + } + + async function uploadImage(e) { + let file = e.target.files[0]; + const { data, error } = await supabase + .storage + .from('images') + .upload(user.id + '/' + uuidv4(), file); + + if (data) { + getImages(); + } else { + console.log(error); + } + } + + async function uploadScreenshot(e) { + let file = image + '.png'; + const { data, error } = await supabase + .storage + .from('images') + .upload(user.id + '/' + uuidv4(), file); + + if (data) { + getImages(); + } else { + console.log(error); + } + } + + async function deleteImage (imageName) { + const { error } = await supabase + .storage + .from('images') + .remove([ user.id + '/' + imageName ]) + + if (error) { + alert (error); + } else { + getImages(); + } + } + + useEffect(() => { + if (user) { // Only get images IF the user exists and is logged in + getImages(); // Add a getPosts function to get a user's profile posts + } + }, [user]); + + function convertURIToImageData(URI) { + return new Promise(function(resolve, reject) { + if (URI == null) return reject(); + var canvas = document.createElement('canvas'), + context = canvas.getContext('2d'), + image = new Image(); + image.addEventListener('load', function() { + canvas.width = image.width; + canvas.height = image.height; + context.drawImage(image, 0, 0, canvas.width, canvas.height); + resolve(context.getImageData(0, 0, canvas.width, canvas.height)); + }, false); + image.src = URI; + }); + } + + /* PLANET manipulation */ + async function createPlanet({ // Maybe we should add a getPlanet (getUserPlanet) helper as well? + userId, temperature, radius, date, ticId + } : { + //id: Planets['id'] + userId: Planets['userId'] // Check to see if this page gets the userId as well, or just the username. Foreign key still works regardless + temperature: Planets['temperature'] + radius: Planets['radius'] + date: Planets['date'] + ticId: Planets['ticId'] + }) { + try { + setLoading(true); + // Is the planet ID going to be based on the user id (obviously not in production, but in this version?) + const newPlanetParams = { + id: user.id, // Generate a random id later + // .. other params from database types + } + } catch (error) { + console.log(error); + } finally { + setLoading(false); + } + } + + async function getUserPlanet() { + try { + setLoading(true); + if (!user) throw new Error('No user authenticated'); + let { data, error, status } = await supabase + .from('planets') + .select(`id, userId, temperature, radius, ticId`) + .eq('userId', username) + .single() + + if (error && status !== 406) { + throw error; + } + + if (data) { + setUserIdForPlanet(data.userId); + } + } catch (error) { + console.log(error); + } finally { + setLoading(false); + } + } + return (
-
+
setUsername(e.target.value)} /> -
+
setWebsite(e.target.value)} - /> -
+ />
+
setAddress(e.target.value)} /> -
+
+

+
+ +
+ {"ScreenShot"} +
} + style={{ + border: "1px solid #ccc", + padding: "10px", + marginTop: "20px" + }} + > +
+
+ + <> +

Your photos


+

Upload image of your model for analysis

+ + uploadImage(e)} /> +
+ +



+

Your images

+ + {images.map((image) => { + return ( + + + + + + + + + ) + })} + + +
- +
) diff --git a/components/Header.tsx b/components/Header.tsx index 450064ed..1f51a5e0 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -12,13 +12,22 @@ export default function Header () { logo - Portal + 🚀 - Github + ⌚️ + + + 🪐 {/* Make submenu items */} - Create + 🎨 + + + 🌌 + + + ⛓
diff --git a/components/Layout.tsx b/components/Layout.tsx new file mode 100644 index 00000000..a36ed4d9 --- /dev/null +++ b/components/Layout.tsx @@ -0,0 +1,15 @@ +import NavigationCard from "./Sidebar"; +import styles from '../../styles/social-graph/Home.module.css'; + +export default function Layout({ children }) { +
+
+
{/* Sidebar */} + +
+
+ {children} +
+
+
+} \ No newline at end of file diff --git a/components/Posts/Avatar.tsx b/components/Posts/Avatar.tsx new file mode 100644 index 00000000..4596e5b3 --- /dev/null +++ b/components/Posts/Avatar.tsx @@ -0,0 +1,66 @@ +import { useSupabaseClient } from '@supabase/auth-helpers-react'; +import styles from '../../styles/social-graph/PostForm.module.css'; +import { Database } from '../../utils/database.types'; +import { useState, useEffect } from 'react'; + +type Profiles = Database['public']['Tables']['profiles']['Row']; + +export default function Avatar () { + return ( +
+
+
+ ) +} + +export function AvatarFromTable ({ + uid, + url, + size +}: { + uid: string, + url: Profiles['avatar_url'] + size: number +}) { + const supabase = useSupabaseClient(); + const [avatarUrl, setAvatarUrl] = useState(null); + + async function downloadImage( path: string ) { + try { + const { data, error } = await supabase.storage.from('avatars').download(path); + if (error) { + throw error; + }; + const url = URL.createObjectURL(data); + setAvatarUrl(url); + } catch (error) { + console.log('Error downloading user avatar: ', error); + } + } + + return ( +
+
+ {avatarUrl ? ( + Avatar + ) : ( +
+ )} + +
+
+ ) +} + +export function BigAvatar () { + return ( +
+
+
+ ) +} \ No newline at end of file diff --git a/components/Posts/Card.tsx b/components/Posts/Card.tsx new file mode 100644 index 00000000..a9e46630 --- /dev/null +++ b/components/Posts/Card.tsx @@ -0,0 +1,13 @@ +import styles from '../../styles/social-graph/Home.module.css'; + +export default function Card ({ children }) { + return ( +
{children}
+ ); +} + +export function ProfileCard ({ children }) { + return ( +
{children}
+ ); +} \ No newline at end of file diff --git a/components/Posts/MessageBoard.tsx b/components/Posts/MessageBoard.tsx new file mode 100644 index 00000000..bf7d898e --- /dev/null +++ b/components/Posts/MessageBoard.tsx @@ -0,0 +1,21 @@ + +import React, { useContext } from "react"; +import { Link, Outlet } from "react-router-dom"; +import { UserContextProvider } from "@supabase/auth-ui-react/dist/esm/src/components/Auth/UserContext"; + +export default function MessageBoard() { + //const userProfile = useContext(UserContext); + return ( +
+ +

Message Board

+ + {/*{userProfile.session ? ( + <> + ) : ( +

You'll need to to join the discussions

+ )} + */} +
+ ) +} \ No newline at end of file diff --git a/components/Posts/PostCard.tsx b/components/Posts/PostCard.tsx new file mode 100644 index 00000000..05cc4ffd --- /dev/null +++ b/components/Posts/PostCard.tsx @@ -0,0 +1,100 @@ +import Card from "./Card"; +import Avatar from "./Avatar"; +import styles from '../../styles/social-graph/PostCard.module.css'; +import { HiOutlineHeart, HiOutlineSpeakerphone, HiOutlineTrash, HiOutlineShare, HiOutlineCamera, HiOutlineDotsHorizontal, HiOutlineSaveAs, HiOutlineBell, HiEyeOff } from 'react-icons/hi' +import ClickOutHandler from 'react-clickout-handler'; +import { useState } from "react"; +import Link from "next/link"; +import { useSupabaseClient, useUser } from "@supabase/auth-helpers-react"; + +export default function PostCard () { + const supabase = useSupabaseClient(); + const [avatar_url, setAvatarUrl] = useState(''); + const user = useUser(); + + const [dropdownOpen, setDropdownOpen] = useState(false); + function openDropdown(e) { + e.stopPropagation(); + setDropdownOpen(true); + } + function handleClickOutsideDropdown (e) { + e.stopPropagation(); + setDropdownOpen(false); + } + + return ( + +
+
+ + + + + +
+
+

Liam Arbuckle shared a post:

+

2 hours ago

+
+
+ {!dropdownOpen && ( + + )} + {dropdownOpen && ( + + )} + +
+ {dropdownOpen && ( +
+ Save post + Get notified {/* Additional updates/data/citations */} + Hide post + Delete post {/* Delete from frontend, will still be there privately on your Lens profile */} + {/* + * Add to dataset/collection + * Inspect dataset + * Clone datapoint + * Remix (in your own playground, either existing or new) + * Reference (in a document/article) + All these action items are stored on-chain! + */} +
+ )} +
+
+
+
+
+

Lorem ipsum doler sit ameet, consectetur adipisicing dol enur im eit heyt gummi thiguh benn hesuoghbseig esgijkhesuogahbesanag asregu heg gehg egw g ds gds g dsg sd g eskjgbse gse g sed gsed gsed g wers ag re hgaer h dsf ghserdahgsrh dsrhdfashfd h fd hsrfd h r hardf h sfdh df h df h fdh f hadfa jh gcf hj dfh fdh hfd h fd hdf h fd h fdhdf hfd h dfr hfd h fd h fdh dra hgfd fh df h haettd htd

+
+
+
{/* Post action buttons section */} + + + +
+
{/* Commenting section */} +
+ +
+
+ + +
+
+
+ ); +} \ No newline at end of file diff --git a/components/Posts/PostFormCard.tsx b/components/Posts/PostFormCard.tsx new file mode 100644 index 00000000..62ade257 --- /dev/null +++ b/components/Posts/PostFormCard.tsx @@ -0,0 +1,138 @@ +import NavigationCard from "../Sidebar" +import Card from "./Card" +import styles from '../../styles/social-graph/PostForm.module.css'; +import { HiUserGroup, HiOutlineMap, HiOutlinePuzzle, HiOutlineTag, HiOutlineTerminal } from 'react-icons/hi'; +import Avatar, { AvatarFromTable } from "./Avatar"; +import { useEffect, useState } from "react"; +import { Auth, ThemeSupa } from "@supabase/auth-ui-react"; +import { useSession, useSupabaseClient, useUser, Session } from "@supabase/auth-helpers-react"; +import AccountAvatar from "../Data/AccountAvatar"; +import { Database } from "../../utils/database.types"; + +type Profiles = Database['public']['Tables']['profiles']['Row']; + +export default function PostFormCard () { + const supabase = useSupabaseClient(); + const user = useUser(); + const [profile, setProfile] = useState(null); + + return ( + +
+ +