Skip to content

Commit

Permalink
feat(client): add authentication, migrations, and some profile settin…
Browse files Browse the repository at this point in the history
…gs. (#193)

* feat: added signin, singup, forgotpassword ui mocks

* feat: supabase auth added.

* feat: migrations with user profile and navbar

* feat: boilerplate ui

* feat: more info about data-collection

* feat: more privacy stuff

* feat: added settings/profile

* fix: fixed types in settings/profile

* feat: avatars

* feat: force user to pick username on signup

* feat: supabase migrations in transactions

* chore: create migration for email subscribers

* chore: remove public routes as they are not needed anymore _app layout handles auth redirects

* chore: disable redirect to sign-in until properly tested sign-in in dev

* fix: fix check for has_username for github oauth

* chore: regenerate supabase types

* fix: add supabase sdk to client
  • Loading branch information
girl-loves-coding authored Nov 4, 2024
1 parent ba1697c commit 8195c3e
Show file tree
Hide file tree
Showing 67 changed files with 4,524 additions and 155 deletions.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,9 @@ dist
.idea/*

# MacOS
.DS_Store
.DS_Store

# Supabase
**/supabase/.temp
**/supabase/.branches
**/supabase/config.toml
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"cSpell.words": ["lucide", "reactflow"]
"cSpell.words": ["lucide", "reactflow", "supabase"]
}
86 changes: 86 additions & 0 deletions packages/client/app/components/auth/auth-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Link, Form } from "@remix-run/react";
import { Button, Input, Label, Separator } from "@data-river/shared/ui";
import { GithubButton } from "./github-button";

interface AuthFormProps {
error?: string;
}

export const AuthForm = ({ error }: AuthFormProps) => {
return (
<div className="space-y-6 mx-auto">
<GithubButton />

<div className="relative">
<div className="absolute inset-0 flex items-center">
<Separator className="w-full" />
</div>
<div className="relative flex justify-center text-sm uppercase">
<span className="bg-background px-2 text-muted-foreground">
or continue with
</span>
</div>
</div>

<Form method="post" className="space-y-5">
{error && (
<div className="text-sm text-red-500 text-center">{error}</div>
)}

<div className="space-y-3">
<Label htmlFor="email" className="text-sm">
Email
</Label>
<Input
id="email"
name="email"
type="email"
placeholder="[email protected]"
required
className="h-11 text-base"
/>
</div>

<div className="space-y-3">
<div className="flex items-center justify-between">
<Label htmlFor="password" className="text-sm">
Password
</Label>
<Button
asChild
variant="link"
className="px-0 font-normal text-sm text-muted-foreground"
>
<Link to="/forgot-password">Forgot Password?</Link>
</Button>
</div>
<Input
id="password"
name="password"
type="password"
placeholder="••••••••••"
required
className="h-11 text-base"
/>
</div>

<Button
type="submit"
className="w-full h-11 bg-focus text-focus-foreground hover:bg-focus/80 text-base"
>
Sign In
</Button>
</Form>

<p className="text-center text-sm text-muted-foreground">
Don't have an account?{" "}
<Link
to="/sign-up"
className="font-medium text-primary hover:underline"
>
Sign Up Now
</Link>
</p>
</div>
);
};
56 changes: 56 additions & 0 deletions packages/client/app/components/auth/forgot-password-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Link, Form } from "@remix-run/react";
import { Button, Input, Label } from "@data-river/shared/ui";

interface ForgotPasswordFormProps {
error?: string;
success?: string;
}

export const ForgotPasswordForm = ({
error,
success,
}: ForgotPasswordFormProps) => {
return (
<div className="space-y-6 mx-auto">
<Form method="post" className="space-y-5">
{error && (
<div className="text-sm text-red-500 text-center">{error}</div>
)}
{success && (
<div className="text-sm text-green-500 text-center">{success}</div>
)}

<div className="space-y-3">
<Label htmlFor="email" className="text-sm">
Email
</Label>
<Input
id="email"
name="email"
type="email"
placeholder="[email protected]"
required
className="h-11 text-base"
/>
</div>

<Button
type="submit"
className="w-full h-11 bg-focus text-focus-foreground hover:bg-focus/80 text-base"
>
Send reset email
</Button>
</Form>

<p className="text-center text-sm text-muted-foreground">
Already have an account?{" "}
<Link
to="/sign-in"
className="font-medium text-primary hover:underline"
>
Sign In
</Link>
</p>
</div>
);
};
21 changes: 21 additions & 0 deletions packages/client/app/components/auth/github-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Button } from "@data-river/shared/ui";
import { Form } from "@remix-run/react";

export const GithubButton = () => {
return (
<Form action="/auth/github" method="post">
<Button variant="outline" type="submit" className="w-full h-11 text-base">
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
className="w-5 h-5 mr-3 fill-current"
>
<title>GitHub</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
Continue with Github
</Button>
</Form>
);
};
11 changes: 11 additions & 0 deletions packages/client/app/components/auth/logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Link } from "@remix-run/react";

const Logo = () => {
return (
<Link to="/" className="flex items-center">
<img src="/assets/images/logo.svg" alt="Data River" className="h-8 w-8" />
</Link>
);
};

export default Logo;
83 changes: 83 additions & 0 deletions packages/client/app/components/auth/sign-up-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Link, Form } from "@remix-run/react";
import { Button, Input, Label, Separator } from "@data-river/shared/ui";
import { GithubButton } from "./github-button";

interface SignUpFormProps {
error?: string;
success?: string;
}

export const SignUpForm = ({ error, success }: SignUpFormProps) => {
return (
<div className="space-y-6 mx-auto">
<GithubButton />

<div className="relative">
<div className="absolute inset-0 flex items-center">
<Separator className="w-full" />
</div>
<div className="relative flex justify-center text-sm uppercase">
<span className="bg-background px-2 text-muted-foreground">
or continue with
</span>
</div>
</div>

<Form method="post" className="space-y-5">
{error && (
<div className="text-sm text-red-500 text-center">{error}</div>
)}
{success && (
<div className="text-sm text-green-500 text-center">{success}</div>
)}

<div className="space-y-3">
<Label htmlFor="email" className="text-sm">
Email
</Label>
<Input
id="email"
name="email"
type="email"
placeholder="[email protected]"
required
className="h-11 text-base"
/>
</div>

<div className="space-y-3">
<div className="flex items-center justify-between">
<Label htmlFor="password" className="text-sm">
Password
</Label>
</div>
<Input
id="password"
name="password"
type="password"
placeholder="••••••••"
required
className="h-11 text-base"
/>
</div>

<Button
type="submit"
className="w-full h-11 bg-focus text-focus-foreground hover:bg-focus/80 text-base"
>
Sign Up
</Button>
</Form>

<p className="text-center text-sm text-muted-foreground">
Have an account?{" "}
<Link
to="/sign-in"
className="font-medium text-primary hover:underline"
>
Sign In Now
</Link>
</p>
</div>
);
};
20 changes: 20 additions & 0 deletions packages/client/app/components/layout/auth-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { NavBar } from "./nav-bar";
import { Testimonial } from "../marketing/testimonial";

interface AuthLayoutProps {
children: React.ReactNode;
}

export const AuthLayout = ({ children }: AuthLayoutProps) => {
return (
<>
<NavBar />
<div className="flex min-h-screen flex-row bg-background">
<div className="flex w-full flex-col justify-center px-6 lg:px-10 xl:px-14">
{children}
</div>
<Testimonial />
</div>
</>
);
};
51 changes: 51 additions & 0 deletions packages/client/app/components/layout/cookie-consent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useState, useEffect } from "react";
import { Button } from "@data-river/shared/ui/components/ui/button";
import { Card, CardContent } from "@data-river/shared/ui/components/ui/card";

export function CookieConsent() {
const [isVisible, setIsVisible] = useState(false);

useEffect(() => {
// Check if user has already made a choice
const cookieChoice = localStorage.getItem("cookie-consent");
if (!cookieChoice) {
setIsVisible(true);
}
}, []);

const handleAccept = () => {
localStorage.setItem("cookie-consent", "accepted");
setIsVisible(false);
};

const handleDecline = () => {
localStorage.setItem("cookie-consent", "declined");
setIsVisible(false);
};

if (!isVisible) return null;

return (
<div className="fixed bottom-4 left-4 right-4 md:left-auto md:right-4 md:max-w-sm z-50">
<Card>
<CardContent className="p-4 space-y-4">
<p className="text-sm">
We use cookies to improve your experience. By using our site, you
agree to our use of cookies.
</p>
<div className="flex gap-2">
<Button variant="default" size="sm" onClick={handleAccept}>
Accept
</Button>
<Button variant="outline" size="sm" onClick={handleDecline}>
Decline
</Button>
<Button variant="ghost" size="sm" asChild>
<a href="/privacy">Learn more</a>
</Button>
</div>
</CardContent>
</Card>
</div>
);
}
22 changes: 22 additions & 0 deletions packages/client/app/components/layout/nav-bar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Button } from "@data-river/shared/ui";
import { FileText } from "lucide-react";
import Logo from "~/components/auth/logo";

export const NavBar = () => {
return (
<div className="fixed left-4 right-4 top-4 flex items-center justify-between">
<Logo />
<Button variant="outline" asChild className="hidden lg:flex">
<a
href="https://docs.data-river.dev"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 rounded-md px-4 py-2 text-sm text-muted-foreground transition-colors hover:text-primary"
>
<FileText className="h-4 w-4" />
Documentation
</a>
</Button>
</div>
);
};
Loading

0 comments on commit 8195c3e

Please sign in to comment.