Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Surreal Poll webapp #32

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions surreal-poll/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# expose client-side environment variables.
# this environment variables are exposed in your bundle.

VITE_DB_HOST=
VITE_DB_USER=
VITE_DB_PASS=

# This token is for when you want to use the Surreal Cloud
# if you want to import the schama's that are already created
# inside the schema folder inside this project.
DB_TOKEN=
3 changes: 3 additions & 0 deletions surreal-poll/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
.env
12 changes: 12 additions & 0 deletions surreal-poll/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Include .env file
-include .env
# Make sure variables are exported
export

apply:
@echo "Applying schema"
$(eval MODIFIED_DB_HOST := $(subst wss://,https://,${VITE_DB_HOST}))
for schema in $(wildcard schema/*.surql); do \
echo "Applying schema: $$schema"; \
surreal import $$schema --namespace surrealdb --database pollwebapp --endpoint ${MODIFIED_DB_HOST} --token ${DB_TOKEN};\
done
143 changes: 143 additions & 0 deletions surreal-poll/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# SurrealPolls 🗳️– Your Gateway to Instant Opinions!

Welcome to **SurrealPolls**, where gathering votes and making decisions has never been easier (or more fun)! Whether you’re planning a group outing, running a class survey, or settling the eternal "pineapple on pizza" debate, we’ve got you covered.

Built with cutting-edge technologies like **SolidJS**, **Vite**, **SurrealDB**, **Surreal Cloud**, and **Tailwind CSS**, this app is as modern as your need for instant polls.

---

## What’s Inside the Polling Magic?

### **Tech Stack Highlights**:
- **SolidJS**: Super snappy frontend framework for blazing-fast performance and reactivity. Your votes will feel instant, and your app will feel buttery smooth.
- **Tailwind CSS**: Your app is not just functional; it’s also pretty, thanks to this utility-first CSS framework.
- **Surreal Cloud**: Surreal Cloud (Beta) transforms the database experience, providing the power and versatility of SurrealDB without the complexity of managing infrastructure.



---

## Features That’ll Make You Smile 😄

### 📝 **Create Polls**
Spin up a poll in seconds. Just give it a title, list out some options, and BOOM! A shareable link is ready for your friends, colleagues, or anyone with an opinion.

### ✅ **Vote Away**
Let your participants cast their votes effortlessly. The app ensures a seamless and real-time voting experience, so nobody’s left waiting.

### 🔒 **End Polls**
Want to close the poll and announce the results? No problem! You’re in control. End the poll whenever you’re ready to seal the deal.

### 📊 **Real-Time Results**
Results update in real-time, giving you instant insights into where everyone stands. No refresh button required!

---

## How to Run This Beauty

### Prerequisites
Make sure you have the following installed:
- [Node.js](https://nodejs.org) (v16+)
- [SurrealDB](https://surrealdb.com) (running locally or remotely)

### Installation
Ready to dive in? Let’s go!

1. Clone the repo:
```bash
git clone https://github.com/your-repo/polling-app.git
cd polling-app
```

2. Install dependencies:
```bash
npm install
```

3. Connect to a SurrealDB Cloud Instance via CLI:

When you have a SurrealDB Cloud instance running, you can [connect to it using the SurrealDB CLI](https://surrealdb.com/docs/cloud/connect/cli) and this will give you an endpoint to use in the make file.

Copy the endpoint without the `surreal sql` prefix as you will be making an import into the database.

```bash
--endpoint <endpoint> --token <token>
```
> We recommend using [Surrealist](https://surrealist.dev) the GUI for SurrealDB Cloud to manage and create your database users.

4. Create a database user in the Authentication section of Surrealist as you will need to use the username and password to connect to the database from the frontend.

4. Mirroring the `.env.example` file, create an `.env` file in the root of the project and set the `VITE_DB_HOST` and `DB_TOKEN` to the endpoint and token you copied from the CLI. Then, set the `VITE_DB_USER` to `root` and `VITE_DB_PASS` to `root`.


5. Apply the schema: Use the included Makefile to set up your database schema:
```bash
make apply
```
This will automatically apply all .surql files in the schema directory to your SurrealDB instance.

5. Configure SurrealDB in `src/lib/providers/surrealdb.tsx` if needed (default is localhost).

6. Run the development server:
```bash
npm run dev
```

7. Open your browser at [http://localhost:3000](http://localhost:3000) and start polling!

---

## File Structure
Here’s how this masterpiece is organized:

```
/surrealpolls
|-- /src
| |-- /assets # Static assets like icons
| |-- /components # Reusable UI components
| | |-- Footer # Footer component
| | |-- Navbar # Navbar component
| |-- /lib # Logic and utility files
| | |-- /providers # Context providers (e.g., surrealdb.tsx)
| | |-- utils.ts # Helper functions
| |-- /pages # Pages for routing (Home, Create Poll, Vote, Results)
| |-- /styles # Global styles (index.css)
| |-- App.tsx # The main app component
| |-- index.tsx # Entry point of the app
| |-- routes.tsx # App routes
|-- /public # Public files (e.g., favicon)
|-- /.env.example # Example env file
|-- Makefile # For schema management
|-- tailwind.config.js # Tailwind configuration
|-- vite.config.ts # Vite configuration
```

---

## Things You Can Try
- **Create Your First Poll**: Go to the “Create Poll” page, add some options, and share the generated link.
- **Test Real-Time Voting**: Open the voting link in two different tabs/devices and watch the magic happen.
- **End a Poll**: Close a poll to stop further voting and see the results instantly.

---

## Why Use This App?
- **Speedy Setup**: It’s quick to build and deploy—thanks to SolidJS and Vite.
- **Beautiful UI**: Tailwind CSS makes everything look polished without extra effort.
- **Powerful Backend**: SurrealDB ensures your data is safe, scalable, and lightning-fast.
- **Open Source**: Customize it to your heart’s content.

---

## Contributing
Feel free to fork the repo, make improvements, and send us a pull request. We’re always open to ideas that make polling better (and cooler)!

---

## License
This project is licensed under the MIT License—because sharing is caring. 😊

---

Happy polling! 🎉

Binary file added surreal-poll/bun.lockb
Binary file not shown.
18 changes: 18 additions & 0 deletions surreal-poll/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="shortcut icon" type="image/ico" href="/src/assets/favicon.ico" />
<title>SurrealDB | Poll webapp </title>
</head>

<body class="bg-gray-400">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/index.tsx" type="module"></script>
</body>

</html>
35 changes: 35 additions & 0 deletions surreal-poll/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "vite-template-solid",
"version": "0.0.0",
"description": "",
"type": "module",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"license": "MIT",
"devDependencies": {
"@types/bun": "latest",
"@types/node": "^22.10.5",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.17",
"typescript": "^5.7.2",
"vite": "^6.0.0",
"vite-plugin-solid": "^2.11.0"
},
"dependencies": {
"@kobalte/core": "^0.13.7",
"@solidjs/router": "^0.15.2",
"@tanstack/solid-query": "^5.62.16",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"solid-js": "^1.9.3",
"surrealdb": "1.1.0",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7"
},
"module": "index.ts"
}
6 changes: 6 additions & 0 deletions surreal-poll/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
8 changes: 8 additions & 0 deletions surreal-poll/schema/poll.surql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DEFINE TABLE poll SCHEMAFULL PERMISSIONS FULL;

-- Title of the poll
DEFINE FIELD title ON poll TYPE string;

-- The creator of the poll (if any)
DEFINE FIELD creator ON poll TYPE option<record<user>>
VALUE $auth.id;
4 changes: 4 additions & 0 deletions surreal-poll/schema/pollHasQuestion.surql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DEFINE TABLE pollHasQuestion SCHEMAFULL
TYPE RELATION
IN poll
OUT question;
3 changes: 3 additions & 0 deletions surreal-poll/schema/pollQuestion.surql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DEFINE TABLE pollQuestion SCHEMAFULL;

DEFINE FIELD question ON pollQuestion TYPE string;
5 changes: 5 additions & 0 deletions surreal-poll/schema/pollVote.surql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DEFINE TABLE pollVote SCHEMAFULL
TYPE RELATION
IN user
OUT pollQuestion;

19 changes: 19 additions & 0 deletions surreal-poll/schema/user.surql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
DEFINE ACCESS user ON DATABASE TYPE RECORD
SIGNUP ( CREATE user SET name = $name, email = $email, password = crypto::argon2::generate($pass) )
SIGNIN ( SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(password, $pass) )
DURATION FOR TOKEN 15m, FOR SESSION 12h
;

DEFINE TABLE user SCHEMAFULL
PERMISSIONS FOR select, update, delete
WHERE $access = "user"
AND id = $auth.id
;

-- Give the user table an email field. Store it in a string
DEFINE FIELD email ON TABLE user
TYPE string
ASSERT string::is::email($value);

DEFINE FIELD name ON TABLE user TYPE string;
DEFINE FIELD password ON TABLE user TYPE string;
46 changes: 46 additions & 0 deletions surreal-poll/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { Component } from 'solid-js';
import { Router, Route } from "@solidjs/router";
import { SurrealProvider } from './lib/providers/surrealdb';
import { QueryClientProvider } from '@tanstack/solid-query';
import { tanstackClient } from './lib/query-client';
import { Navbar } from './components/Navbar';
import { AuthProvider } from './lib/providers/auth';
import Home from './pages/Home';
import CreatePoll from './pages/CreatePoll';
import VotePoll from './pages/VotePoll';
import PollResults from './pages/PollResults';
import { AppLayout } from './components/layout/app';
import { Signin } from './pages/Signin';
import { Signup } from './pages/Signup';
import { Toaster } from './components/ui/toast';

const App: Component = () => {
return (
<QueryClientProvider client={tanstackClient}>
<SurrealProvider
endpoint={import.meta.env.VITE_DB_HOST}
autoConnect
params={{
namespace: "surrealdb",
database: "pollwebapp",
}}
>
<AuthProvider>
<Router>
<Route path="/" component={AppLayout}>
<Route path="/" component={Home} />
<Route path="/create" component={CreatePoll} />
<Route path="/poll/:id" component={VotePoll} />
<Route path="/poll/:id/results" component={PollResults} />
<Route path="/signin" component={Signin} />
<Route path="/signup" component={Signup} />
</Route>
</Router>
<Toaster />
</AuthProvider>
</SurrealProvider>
</QueryClientProvider>
);
};

export default App;
Binary file added surreal-poll/src/assets/favicon.ico
Binary file not shown.
Empty file.
40 changes: 40 additions & 0 deletions surreal-poll/src/components/Navbar/avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Avatar, AvatarFallback } from "../ui/avatar";
import { useAuth } from "~/lib/providers/auth";
import { For, Show } from "solid-js";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuShortcut, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { A } from "@solidjs/router";

export function NavbarAvatar() {

// const { client } = useSurreal();
const { user, logout } = useAuth();

return (
<DropdownMenu placement="left-start">
<DropdownMenuTrigger>
<Avatar>
<AvatarFallback>
{(user()?.name ?? "U").slice(0, 1).toUpperCase()}
</AvatarFallback>
</Avatar>
</DropdownMenuTrigger>
<DropdownMenuContent class="w-48">
<Show
when={!user()}
fallback={
<DropdownMenuItem onClick={logout}>
Logout
</DropdownMenuItem>
}
>
<DropdownMenuItem>
<A class="w-full" href="/signin">Signin</A>
</DropdownMenuItem>
<DropdownMenuItem>
<A class="w-full" href="/signup">Signup</A>
</DropdownMenuItem>
</Show>
</DropdownMenuContent>
</DropdownMenu>
);
}
20 changes: 20 additions & 0 deletions surreal-poll/src/components/Navbar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useSurreal } from "~/lib/providers/surrealdb";
import { NavbarAvatar } from "./avatar";
import { A } from "@solidjs/router";

export function Navbar() {

const { } = useSurreal();

return (
<header class="p-4 flex justify-between shadow-md items-center">
<A href="/">
Home
</A>
<A href="/create">
Create Poll
</A>
<NavbarAvatar />
</header>
);
}
Loading