Fetching users from Supabase results in /undefined user page - next.js

I am creating a directory of users in Next.js. The users are stored in Supabase. I need for all the users to be displayed in the index.js file, looping through them and showing them on a grid. This is working with getStaticProps, fetching the data and passing it as props profiles.
However, when clicking on each profile, it does redirect me to the [id].js page, but it appends /undefined to the url, rather than the id.
My file tree looks as follows:
pages
people
index.js
[id].js
export default function People({ profiles }) {
return (
<div className="body min-h-[90vh]">
<Head>
<title>People</title>
<link rel="icon" href="/logo" />
</Head>
<div
key={profiles.id}
profiles={profiles}
className="flex flex-col items-center py-16"
>
<div className="grid md:grid-flow-col md:grid-cols-3 xl:grid-cols-4 gap-8 lg:gap-12">
{profiles.map((profile) => (
<Link href={`/people/${profiles.id}`} key={profiles.id}>
<div
profile={profile}
id={profile.id}
className="flex flex-col w-full justify-center items-center p-8 shadow-md hover:shadow-lg"
>
{profile.avatar_url && (
<Image
src={profile.avatar_url}
alt="profile picture"
width={200}
height={200}
className="rounded-full"
object-fit="cover"
/>
)}
<h1 className="text-2xl pt-8 text-center">
{profile.full_name}
</h1>
<p>{profile.skills.skill}</p>
<button className="button w-full">See lessons</button>
</div>
</Link>
))}
</div>
</div>
</div>
);
}
export async function getStaticProps() {
const supabaseAdmin = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL || "",
process.env.SUPABASE_SERVICE_ROLE_KEY || ""
);
const { data } = await supabaseAdmin
.from("profiles")
.select("*, skills(skill)")
.order("id");
console.log(data);
return {
props: {
profiles: data,
},
};
}
Any ideas as to what I am doing wrong are highly appreciated.
Thanks.

Related

Popover on table rendering multiple instances in Vue3

I am trying to create a Vue component which wraps a Popoverfrom headlessui
I am trying to toggle open close using the slot binding as suggested in the popover docs. I cannot get this to work. Nothing appears in the UI, even if I had it working ok from within the element itself, granted that is neither a good place to put it because the elements render as many rows there are in the table.
Does anyone have any wisdom surrounding headless UI popovers in Vue3 on a table row?
EDIT:
Ok adding static to the PopoverPanelmakes it render when open=true
, the issue now being that multiple instances render based on the number of elements in the table. So this is a new issue.
<template>
<div>
<Popover :slot="{pop}">
<transition
enter-active-class="transition duration-200 ease-out"
enter-from-class="translate-y-1 opacity-0"
enter-to-class="translate-y-0 opacity-100"
leave-active-class="transition duration-150 ease-in"
leave-from-class="translate-y-0 opacity-100"
leave-to-class="translate-y-1 opacity-0"
>
<PopoverPanel static class="absolute z-9 mt-3 max-w-sm -translate-x-1/2 transform sm:px-0 lg:max-w-3xl">
<div class="rounded-lg shadow-lg w-full m-2">
<div
v-if="pop"
ref="popover"
class="flex flex-col p-2"
>
<ButtonTemp label="Send reminder" btn-type="m-0.5 bg-neutral-200 text-neutral-900 text-left text-caption hover:bg-neutral-900 hover:text-neutral-100" icon-left>
<IconsMail />
</ButtonTemp>
<ButtonTemp label="Share candidate" btn-type="m-0.5 bg-neutral-200 text-neutral-900 text-caption hover:bg-neutral-900 hover:text-neutral-100" icon-left>
<IconsExternalLink />
</ButtonTemp>
<ButtonTemp label="Remove from assignment" btn-type="m-0.5 bg-neutral-200 text-neutral-900 text-caption hover:bg-danger-100 hover:text-neutral-100" icon-left>
<IconsUserMinus />
</ButtonTemp>
</div>
</div>
</PopoverPanel>
</transition>
</Popover>
<script setup lang="ts">
import { Ref } from '#vue/runtime-core';
import { Popover, PopoverButton, PopoverPanel } from '#headlessui/vue';
import { ButtonTemp, IconsMail, IconsExternalLink, IconsUserMinus } from '#/.nuxt/components';
const pop: Ref<boolean> = ref(true);
interface IContextMenu {
open: boolean;
}
const props = defineProps<IContextMenu>();
const isOpen = toRef(props, 'open');
watch(isOpen, (is) => {
if (is) {
console.log('open', is);
pop.value = !pop.value;
}
});
onMounted(() => {
pop.value = true;
});
</script>
Component where it is to be used:
......
<td class="group-hover:text-neutral-100 rounded-r">
<button
class="m-auto h-8 w-8 rounded-sm flex justify-center items-center group-hover:bg-neutral-700 cursor-pointer"
#click="handleClick(candidate.id, '')"
>
<ContextMenu :open="open" /> // Popover wrapped component
<IconsVerticalMenu />
</button>
</td>
</tr>

I connected my database, .net c# and react typescript project, how do print out all elements from database with onClick function?

// I am trying to print out the database elements to react typescript home page, but when i print // it out it prints out
// [Object] [Object].
function HomePage(){
const [games, setGames] = useState< IGame []>([]);
useEffect(() => {
GameService.GetAllGames().then((data) => setGames(data));
}, []);
function onClickCreateADivWithGamesInfromation(){
const div = document.createElement('div');
const informationAboutGames = document.createElement('information');
informationAboutGames.innerText = `
${games.map((game, index) => {
return <GamesItem key={index} {...game} />
})}`;
JSON.stringify(informationAboutGames);
div.appendChild(informationAboutGames);
document.body.appendChild(div);
}
return(
<div>
<header>
<h1 className='text-center mb-5 '>Electric games</h1>
</header>
<br />
<main>
<div className='text-center'>
<h3 className='text-center'>Show all games</h3>
<button className='btn btn-primary' onClick={onClickCreateADivWithGamesInfromation} >Show all</button>
</div>

Google Photos API - Automatic Scaling?

I've been making a website to showcase my personal photography, and I've been getting my photos from Google Photos, using their features. (There's a medium post on how to do this)!
However, one problem I have been having is with scaling. I would like my images to be as quality as possible but also at a small enough size for them to fit into a grid on my page. However, when I use the built in parameters to do this (according to the docs) scaling is not preserved!
Example:
My page's code is as follows:
const axios = require('axios');
const Image = require('next/image');
const _ = require('lodash');
export default function Home({ pictures }) {
return (
<div>
<div className="hero min-h-screen" style={{ backgroundImage: 'url(https://lh3.googleusercontent.com/wwilPCF5L98Osl7_HVohVi34EP4SHUNKbxCe-fBooyNcTdvAWawcP3paqGxvAW3gCzXBl4aQOT_oxwYuXXaMG3ICM7cOkWJH6eYcozUqr9agShnjQu8kWFsPxtL7WD7H5sF5rkR9Vdk=w2048)' }}>
<div className="hero-overlay bg-opacity-60" />
<div className="hero-content text-center text-neutral-content">
<div className="max-w-md">
<h1 className="mb-5 text-5xl font-bold">Photography</h1>
<p className="mb-5">Aside from programming, I also love photography! </p>
</div>
</div>
</div>
<div className="flex flex-col flex-wrap m-10">
<div className="flex flex-row basis-1 flex-wrap m-4">
{
pictures.map(((x) => (
<img src={`${x}`} alt="Hello." key={`${x}?`} className=" flex-col flex-auto m-3 rounded-md shadow-md" />
)))
}
</div>
</div>
</div>
);
}
export async function getServerSideProps({ req, res }) {
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
const regex = /\["(https:\/\/lh3\.googleusercontent\.com\/[a-zA-Z0-9\-_]*)"/g;
function extractPhotos(content) {
const links = new Set();
let match;
while (match = regex.exec(content)) {
links.add(match[1]);
}
return Array.from(links);
}
async function getAlbum(id) {
const response = await axios.get(`https://photos.app.goo.gl/${id}`);
const photos = _.shuffle(extractPhotos(response.data));
return photos;
}
const pictures = await getAlbum('ZbGaHdrs62q5Jyrk8');
return {
props: { pictures }, // will be passed to the page component as props
};
}
How can I ensure the images are properly scaled? Is this even possible? Will I need some CSS trick? Thanks!

Dynamic classes with tailwind and clsx [duplicate]

I'm just learning React and Tailwind CSS and had a strange experience with CSS grid using Tailwind classes. I've made the buttons for a calculator, with the last Button spanning two columns:
App.js:
export default function App() {
return (
<div className="flex min-h-screen items-center justify-center bg-blue-400">
<Calculator />
</div>
);
}
Calculator.js
import { IoBackspaceOutline } from "react-icons/io5";
export const Calculator = () => {
return (
<div className="grid grid-cols-4 grid-rows-5 gap-2">
<Button>AC</Button>
<Button>
<IoBackspaceOutline size={26} />
</Button>
<Button>%</Button>
<Button>รท</Button>
<Button>7</Button>
<Button>8</Button>
<Button>9</Button>
<Button>x</Button>
<Button>4</Button>
<Button>5</Button>
<Button>6</Button>
<Button>-</Button>
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
<Button>+</Button>
<Button>0</Button>
<Button>.</Button>
<Button colSpan={2}>=</Button>
</div>
);
};
const Button = ({ colSpan = 1, rowSpan = 1, children }) => {
return (
<div
className={`col-span-${colSpan} row-span-${rowSpan} bg-white p-3 rounded`}
>
<div className="flex items-center justify-center">{children}</div>
</div>
);
};
This doesn't work (tested in Chrome):
Now here comes the weird part. I replaced the returned JSX from the App component with HTML from a Tailwind tutorial and deleted it again.
<div className="bg-blue-400 text-blue-400 min-h-screen flex items-center justify-center">
<div className="grid grid-cols-3 gap-2">
<div className="col-span-2 bg-white p-10 rounded">1</div>
<div className="bg-white p-10 rounded">2</div>
<div className="row-span-3 bg-white p-10 rounded">3</div>
<div className="bg-white p-10 rounded">4</div>
<div className="bg-white p-10 rounded">5</div>
<div className="bg-white p-10 rounded">6</div>
<div className="col-span-2 bg-white p-10 rounded">7</div>
<div className="bg-white p-10 rounded">8</div>
<div className="bg-white p-10 rounded">9</div>
</div>
</div>
After I Ctrl-Z'd a bunch of times, so I had only the previous code, my button suddenly spans two columns as intended:
I checked to make sure that there were no changes in the code:
My friend even cloned my repo, followed the same steps and got the same result.
He suspects that it has something to do with the variable classNames in my Button component with regards to Tailwind's JIT compiler, but none of us can pinpoint the error.
Am I using variable CSS classes wrong?
This has been a WTF moment. What could be the reason for this?
The CSS file generated by Tailwind will only include classes that it recognizes when it scans your code, which means that dynamically generated classes (e.g. col-span-${colSpan}) will not be included.
If you only need to span 2 columns, you could pass boolean values which will trigger the addition of a full col-span-2 or row-span-2 utility class to be added:
const Button = ({ colSpan = false, rowSpan = false, children }) => {
return (
<div
className={`${colSpan ? 'col-span-2' : ''} ${rowSpan ? 'row-span-2' : ''} bg-white p-3 rounded`}
>
<div className="flex items-center justify-center">{children}</div>
</div>
);
};
Otherwise, you could pass the values as classes to the Button component:
<Button className='col-span-2 row-span-1'>=</Button>
const Button = ({ className, children }) => {
return (
<div
className={`${className} bg-white p-3 rounded`}
>
<div className="flex items-center justify-center">{children}</div>
</div>
);
};
More information: https://tailwindcss.com/docs/content-configuration#dynamic-class-names
Another tricky solution that worked for me is to use variable with forced type of the possible className values (in typescript) like :
export type TTextSizeClass =
'text-xl' |
'text-2xl' |
'text-3xl' |
'text-4xl' |
'text-5xl' |
'text-6xl' |
'text-7xl' |
'text-8xl' |
'text-9xl'
;
...
const type : number = 6 ;
const textSizeClass : TTextSizeClass = type != 1 ? `text-${type}xl` : 'text-xl';
...
<div className={`font-semibold ${textSizeClass} ${className}`}>text</div>
As Ed Lucas said:
The CSS file generated by Tailwind will only include classes that it recognizes when it scans your code, which means that dynamically generated classes (e.g. col-span-${colSpan}) will not be included
But now could use safeListing
and
tailwind-safelist-generator package to "pregenerate" our dynamics styles.
With tailwind-safelist-generator, you can generate a safelist.txt file for your theme based on a set of patterns.
Tailwind's JIT mode scans your codebase for class names, and generates
CSS based on what it finds. If a class name is not listed explicitly,
like text-${error ? 'red' : 'green'}-500, Tailwind won't discover it.
To ensure these utilities are generated, you can maintain a file that
lists them explicitly, like a safelist.txt file in the root of your
project.

ReferenceError: firebase is not defined error when using onAuthStateChanged

EDIT #2
So I now have the following https://gist.github.com/benbagley/ef13bc70c62f2cc367561e3927a368fd
The error I am getting is
Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app).
I am only initialising firebase in the firebase.js file nowhere else.
EDIT
Here's a GIF on what's happening:
https://i.gyazo.com/0446e6b492aae300870a32f8bb2b2aa8.mp4
Hi I'm using Nuxt to build a test app however I am getting the following error
[Vue warn]: Error in created hook: "ReferenceError: firebase is not defined"
In Nuxt I have an app.html file with firebase being linked in the rest of the app like so
index.vue
<template>
<section class="flex h-screen w-screen uppercase shadow leading-loose">
<section id="large-header" class="relative w-full overflow-hidden bg-cover bg-center gradient-background">
<canvas id="demo-canvas"></canvas>
<section class="flex flex-wrap w-full max-w-xs absolute m-0 bg-white shadow content">
<section v-if="authUser" class="bg-white p-8">
<h2 class="text-3xl text-black">Signed in as {{ authUser.email }}</h2>
<button #click='signOut' class="twitch flex justify-center items-center p-8 uppercase text-white font-semibold tracking-wide w-full">
Sign Out
</button>
</section>
<section class="pt-4 pl-4 pb-0 pr-4" v-else>
<tabs class="flex flex-wrap border-b w-full pt-2">
<tab name="Sign In">
<SignIn style="outline:none" />
</tab>
<tab name="Sign Up">
<SignUp style="outline:none" />
</tab>
</tabs>
</section>
<button class="twitch flex justify-center items-center p-8 uppercase text-white font-semibold tracking-wide w-full">
<i class="fab fa-twitch pr-2 text-xl"></i> Twitch
</button>
</section>
</section>
</section>
</template>
<script>
import SignIn from '#/components/Forms/SignIn'
import SignUp from '#/components/Forms/SignUp'
import {Tabs, Tab} from 'vue-tabs-component';
export default {
components: {
SignIn,
SignUp,
Tabs,
Tab
},
data: function () {
return {
authUser: null
}
},
methods: {
signOut () {
firebase.auth().signOut()
}
},
created () {
firebase.auth().onAuthStateChanged(user => { this.authUser = user })
}
}
</script>
The line that is causing the issue is this
firebase.auth().onAuthStateChanged(user => { this.authUser = user })
Sign up work and so does sign in however when I add the above line the entire app just crashes producing the following error
[Vue warn]: Error in created hook: "ReferenceError: firebase is not defined"
Any help is appreciated!
Typically, you would install the Firebase SDK via
npm install --save firebase
(or yarn if that's your thing)
Then you import it where required like any other module.
I recommend creating a module for your firebase app that can be imported elsewhere, for example, say in src/firebase.js
import firebase from 'firebase' // import the sdk
// initialise your app
export default firebase.initializeApp({
apiKey: "REDACTED",
authDomain: "dashboard-nuxt-test.firebaseapp.com",
databaseURL: "https://dashboard-nuxt-test.firebaseio.com",
projectId: "dashboard-nuxt-test",
storageBucket: "dashboard-nuxt-test.appspot.com",
messagingSenderId: "1234567890"
})
then in your components
import firebase from '#/firebase'
// and later
firebaseApp.auth().onAuthStateChanged(user => { this.authUser = user })

Resources