Skip to content
Merged
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
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@ yarn run dev
```

🚀 The dev site will be running locally at `localhost:3000` 🚀.

#### Environment
You'll need some credentials to get up and running properly.

Create a `.env` file in the same directory as your `package.json`, as follows.
```env
DATABASE_URL="postgresql://<your-connection-info>"
SHADOW_DATABASE_URL="postgresql://<your-shadow-connection-info"
CHECKPOINT_DISABLE=1
SIGNING_PASSPHRASE="<a-generated-passphrase>"
NEXTAUTH_SECRET="<a-generated-passphrase>"
EMAIL_SERVER="smtp://<your-email-smtp-info>"
FROM_EMAIL="investors@tincre.com"
NEXTAUTH_URL=http://localhost:3000
```

### Tests

Tests leverage `jest` and Kent Dodd's `react testing library`. These can
Expand Down Expand Up @@ -87,11 +103,11 @@ This is handled seamlessly within via the next-auth library.
Right now we offer the following authentication providers:

- direct-to-email link,
- Google Accounts,
- Github,
- Gitlab,
- Microsoft,
- and Twitter.
- (coming soon) Google Accounts,
- (coming soon) Github,
- (coming soon) Gitlab,
- (coming soon) Microsoft,
- (coming soon) and Twitter.

We can and will add more at a later date.

Expand Down
36 changes: 35 additions & 1 deletion __tests__/index.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,44 @@

import { render, screen } from "@testing-library/react";
import Index from "../pages/index";
import { SessionProvider } from "next-auth/react";

export const mockSession = {
data: {
session: {
user: {
image: null,
name: "John",
email: "john@email.com",
},
expires: 123213139,
status: "loading",
},
},
};
describe("Index", () => {
it("should render the page", () => {
render(<Index />);
render(
<SessionProvider session={mockSession}>
<Index />
</SessionProvider>
);

const headingArray = screen.getAllByRole("heading");

headingArray.map((heading) => {
expect(heading).toBeInTheDocument();
});
});
});

describe("Index", () => {
it("should render the page", () => {
render(
<SessionProvider session={undefined}>
<Index />
</SessionProvider>
);

const headingArray = screen.getAllByRole("heading");

Expand Down
19 changes: 11 additions & 8 deletions components/FactSnippetsHero.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { signIn, signOut } from "next-auth/react";

export default function FactSnippetsHero({
subTitle,
title,
description,
cta1,
cta2,
cta1Href,
cta2Href,
session,
}) {
return (
<div className="max-w-3xl mx-auto mb-12 lg:mb-16 text-center">
Expand All @@ -23,12 +24,14 @@ export default function FactSnippetsHero({
>
{cta1}
</a>
<a
className="block md:inline-block px-5 py-3 text-sm font-semibold text-indigo-500 hover:text-white hover:bg-indigo-500 border border-indigo-500 hover:border-indigo-600 rounded transition duration-200"
href={cta2Href}
>
{cta2}
</a>
{!!session ? (
<button
className="block md:inline-block px-5 py-3 text-sm font-semibold text-indigo-500 hover:text-white hover:bg-indigo-500 border border-indigo-500 hover:border-indigo-600 rounded transition duration-200"
onClick={() => signIn()}
>
Log in
</button>
) : null}
</div>
</div>
);
Expand Down
32 changes: 25 additions & 7 deletions components/Hero.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
export default function Hero({ heading, subHeading, cta1, cta2, imageSrc }) {
import { signIn, signOut } from "next-auth/react";

export default function Hero({
heading,
subHeading,
cta1,
cta2,
imageSrc,
session,
}) {
return (
<div className="flex flex-wrap items-center -mx-4 mt-10 lg:my-10 pb-10 lg:pb-16">
<div className="w-full md:w-1/2 px-4 mb-12 md:mb-0">
Expand All @@ -15,12 +24,21 @@ export default function Hero({ heading, subHeading, cta1, cta2, imageSrc }) {
>
{cta1}
</a>
<a
className="block lg:inline-block px-5 py-3 text-sm text-center font-semibold text-indigo-500 hover:text-white hover:bg-indigo-500 border border-indigo-500 hover:border-indigo-600 rounded transition duration-200"
href="#"
>
{cta2}
</a>
{!session ? (
<button
className="block lg:inline-block px-5 py-3 text-sm text-center font-semibold text-indigo-500 hover:text-white hover:bg-indigo-500 border border-indigo-500 hover:border-indigo-600 rounded transition duration-200"
onClick={() => signIn()}
>
Log in
</button>
) : (
<button
className="block lg:inline-block px-5 py-3 text-sm text-center font-semibold text-indigo-500 hover:text-white hover:bg-indigo-500 border border-indigo-500 hover:border-indigo-600 rounded transition duration-200"
onClick={() => signOut()}
>
Log out
</button>
)}
</div>
</div>
<div className="w-full md:w-1/2 px-4">
Expand Down
1 change: 1 addition & 0 deletions components/MobileNavbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default function MobileNavbar({
navigationLinks,
navigationHrefs,
cta,
session,
}) {
return (
<div className="hidden navbar-menu fixed top-0 left-0 bottom-0 w-5/6 max-w-sm z-50">
Expand Down
23 changes: 17 additions & 6 deletions components/Navbar.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import NavigationItem from "./NavigationItem";
import { signIn, signOut } from "next-auth/react";

export default function Navbar({
entityTitle,
navigationLinks,
navigationHrefs,
cta,
session,
}) {
return (
<nav className="flex justify-between items-center py-8">
Expand Down Expand Up @@ -47,12 +49,21 @@ export default function Navbar({
}
})}
</ul>
<a
className="hidden lg:block px-5 py-3 text-sm font-semibold text-indigo-500 hover:text-white hover:bg-indigo-500 border border-indigo-500 hover:border-indigo-600 rounded transition duration-200"
href="#"
>
{cta}
</a>
{!session ? (
<button
className="hidden lg:block px-5 py-3 text-sm font-semibold text-indigo-500 hover:text-white hover:bg-indigo-500 border border-indigo-500 hover:border-indigo-600 rounded transition duration-200"
onClick={() => signIn()}
>
Log in
</button>
) : (
<button
className="hidden lg:block px-5 py-3 text-sm font-semibold text-indigo-500 hover:text-white hover:bg-indigo-500 border border-indigo-500 hover:border-indigo-600 rounded transition duration-200"
onClick={() => signOut()}
>
Log out
</button>
)}
</nav>
);
}
1 change: 1 addition & 0 deletions components/Sections/FactSnippets.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default function FactSnippets({
cta1Href,
cta2Href,
factSnippetsCardContent,
session,
}) {
return (
<section id="fact-snippets" className="py-20">
Expand Down
4 changes: 4 additions & 0 deletions components/Sections/NavigationHero.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default function NavigationHero({
navigationLinks,
navigationHrefs,
cta,
session,
}) {
return (
<section id="navigation-hero">
Expand All @@ -16,20 +17,23 @@ export default function NavigationHero({
navigationLinks={navigationLinks}
navigationHrefs={navigationHrefs}
cta={cta}
session={session}
/>
<Hero
heading="We're a different kind of online business."
subHeading="We create value across the web via financially performant semi-autonomous brands centered around core technology."
cta1="Learn about our raise"
cta2="Sign in or up"
imageSrc="https://res.cloudinary.com/tincre/image/upload/v1638892843/tincre.com/tincre-brand-indigo-800_uatfej.svg"
session={session}
/>
</div>
<MobileNavbar
entityTitle={entityTitle}
navigationLinks={navigationLinks}
navigationHrefs={navigationHrefs}
cta={cta}
session={session}
/>
</section>
);
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"react-dom": "^17.0.2"
},
"devDependencies": {
"@next-auth/prisma-adapter": "^1.0.1",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"autoprefixer": "^10.4.2",
Expand All @@ -23,6 +24,8 @@
"jwt-decode": "^3.1.2",
"localforage": "^1.10.0",
"nanoid": "^3.2.0",
"next-auth": "^4.1.2",
"nodemailer": "^6.7.2",
"postcss": "^8.4.5",
"prisma": "^3.8.1",
"swr": "^1.2.0",
Expand Down
9 changes: 7 additions & 2 deletions pages/_app.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import "../styles/global.css";
import { SessionProvider } from "next-auth/react";

function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
);
}

export default MyApp;
19 changes: 19 additions & 0 deletions pages/api/auth/[...nextauth].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {PrismaAdapter} from "@next-auth/prisma-adapter"
import {PrismaClient} from "@prisma/client"
import NextAuth from "next-auth"
import EmailProvider from "next-auth/providers/email"

const prisma = new PrismaClient()

export default NextAuth({
adapter : PrismaAdapter(prisma),
secret : process.env.NEXTAUTH_SECRET,
providers : [
EmailProvider({
server : process.env.EMAIL_SERVER,
from : process.env.FROM_EMAIL || 'investors@tincre.com',
maxAge : 600, // in seconds
}),
],
debug : false,
})
70 changes: 39 additions & 31 deletions pages/index.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState, useRef, useEffect } from "react";
import { fetcher, clientJwtDecode } from "../lib/utils";
import { useSession, signIn, signOut } from "next-auth/react";
import localforage from "localforage";
import useSwr, { mutate } from "swr";
import Footer from "../components/Footer";
Expand Down Expand Up @@ -39,6 +40,7 @@ export default function Funded() {
const [inputError, setInputError] = useState(false);
const [message, setMessage] = useState("");
const [subscribed, setSubscribed] = useState(false);
const { data: session, status } = useSession();
const hostname = "investor.tincre.com";
const subscribe = async (e) => {
e.preventDefault();
Expand Down Expand Up @@ -149,40 +151,46 @@ export default function Funded() {
navigationLinks={navigationLinks}
navigationHrefs={navigationHrefs}
cta={cta}
session={session}
/>
<Stats1 data={stats1Data} />
<WhyInvest {...whyInvestContent} />
<FactCards factCardsContent={factCardsContent} />
<Stats1 data={stats1Data} />
<FactSnippets
title="Learn about the most awesome company on the floating rock we all call earth"
subTitle="Growing Growth"
description="We're so performant that diversification is just an added cost to you and your portfolio. Displace underperforming assets by writing them down, collecting your tax loss, and reinvesting those proceeds into Tincre."
cta1="Invest now"
cta1Href="#invest"
cta2="Log in"
cta2Href="#login"
factSnippetsCardContent={factSnippetsCardContent}
/>
<InfoBlock
title="Actually make some money on a new venture, for once."
description="A short message that will bring potential investors into your company's world. And one that will allow them to become more familiar with your story."
cta="Invest in Tincre"
ctaHref="#invest"
/>
<Team
title="Superior people build superior businesses"
subTitle="Better People"
description="Your investments in half-drunk HYP school morons haven't worked out consistently. So change the pace and stop wasting your resources. Invest in the actual top of the class."
teamCardContent={teamCardContent}
/>
<FAQ fAQCardContent={fAQCardContent} />
<InfoBlock
title="One investment to rule them all."
description="Don't miss this opportunity to clean up your horrific past performance and log a win in your P&L. Plus, all your friends will just love doing the same. A win win, by any measure."
cta={`Do one good thing before you croak: invest in ${entityTitle}`}
ctaHref="#invest"
/>
{!session ? null : (
<>
<FactCards factCardsContent={factCardsContent} />
<Stats1 data={stats1Data} />
<FactSnippets
title="Learn about the most awesome company on the floating rock we all call earth"
subTitle="Growing Growth"
description="We're so performant that diversification is just an added cost to you and your portfolio. Displace underperforming assets by writing them down, collecting your tax loss, and reinvesting those proceeds into Tincre."
cta1="Invest now"
cta1Href="#invest"
cta2="Log in"
cta2Href="#login"
factSnippetsCardContent={factSnippetsCardContent}
session={session}
/>
<InfoBlock
title="Actually make some money on a new venture, for once."
description="A short message that will bring potential investors into your company's world. And one that will allow them to become more familiar with your story."
cta="Invest in Tincre"
ctaHref="#invest"
/>
<Team
title="Superior people build superior businesses"
subTitle="Better People"
description="Your investments in half-drunk HYP school morons haven't worked out consistently. So change the pace and stop wasting your resources. Invest in the actual top of the class."
teamCardContent={teamCardContent}
/>
<FAQ fAQCardContent={fAQCardContent} />
<InfoBlock
title="One investment to rule them all."
description="Don't miss this opportunity to clean up your horrific past performance and log a win in your P&L. Plus, all your friends will just love doing the same. A win win, by any measure."
cta={`Do one good thing before you croak: invest in ${entityTitle}`}
ctaHref="#invest"
/>
</>
)}
<Footer
entityTitle={entityTitle}
logoSrc={logoSrc}
Expand Down
Loading