[style] Rename and take out unneeded parts.
This commit is contained in:
parent
18ff9fdd9b
commit
92ae97a57b
94
README.md
94
README.md
@ -1,53 +1,17 @@
|
||||
<p align="center" style="margin-top: 12px">
|
||||
<a href="https://splitpro.app">
|
||||
<img width="100px" style="border-radius: 50%;" src="https://splitpro.app/logo_circle.png" alt="SplitPro Logo">
|
||||
</a>
|
||||
# An open source alternative to Splitwise
|
||||
|
||||
<h1 align="center">SplitPro</h1>
|
||||
<h2 align="center">An open source alternative to Splitwise</h2>
|
||||
## TODO
|
||||
|
||||
<p align="center">
|
||||
<a href="https://splitpro.app"><strong>To our App »</strong></a>
|
||||
<br />
|
||||
<br />
|
||||
</p>
|
||||
</p>
|
||||
- [ ] Add expenses with an individual or groups
|
||||
- [ ] Overall balances across the groups
|
||||
- [ ] Multiple currency support
|
||||
- [ ] Upload expense bills
|
||||
- [ ] PWA support
|
||||
- [ ] Split expense unequally (share, percentage, exact amounts, adjustments)
|
||||
- [ ] Push notification
|
||||
- [ ] Download your data
|
||||
- [ ] Import from splitwise
|
||||
|
||||
## About
|
||||
|
||||
SplitPro aims to provide an open-source way to share expenses with your friends.
|
||||
|
||||
It's meant to be a complete replacement for Splitwise.
|
||||
|
||||
It currently has most of the important features.
|
||||
|
||||
- Add expenses with an individual or groups
|
||||
- Overall balances across the groups
|
||||
- Multiple currency support
|
||||
- Upload expense bills
|
||||
- PWA support
|
||||
- Split expense unequally (share, percentage, exact amounts, adjustments)
|
||||
- Push notification
|
||||
- Download your data
|
||||
- Import from splitwise
|
||||
|
||||
**More features coming every day**
|
||||
|
||||
---
|
||||
|
||||
## Why
|
||||
|
||||
Splitwise is one of the best apps to add expenses and bills.
|
||||
|
||||
I understand that every app needs to make money, After all, lots of effort has been put into Splitwise. My main problem is how they implemented this.
|
||||
|
||||
Monetising on pro features or ads is fine, but asking money for adding expenses (core feature) is frustrating.
|
||||
|
||||
I was searching for other open-source alternatives (Let's be honest, any closed-source product might do the same and I don't have any reason to believe otherwise).
|
||||
|
||||
I managed to find a good app [spliit.app](https://spliit.app/) by [Sebastien Castiel](https://scastiel.dev/) but it's not a complete replacement and didn't suit my workflow sadly. Check it out to see if it fits you.
|
||||
|
||||
_That's when I decided to work on this_
|
||||
|
||||
## Tech stack
|
||||
|
||||
@ -67,20 +31,6 @@ _That's when I decided to work on this_
|
||||
- PostgreSQL
|
||||
- pnpm (recommended)
|
||||
|
||||
## Docker
|
||||
|
||||
We provide a Docker container for Splitpro, which is published on both DockerHub and GitHub Container Registry.
|
||||
|
||||
DockerHub: [https://hub.docker.com/r/ossapps/splitpro](https://hub.docker.com/r/ossapps/splitpro)
|
||||
|
||||
GitHub Container Registry: [https://ghcr.io/oss-apps/splitpro](https://ghcr.io/oss-apps/splitpro)
|
||||
|
||||
You can pull the Docker image from either of these registries and run it with your preferred container hosting provider.
|
||||
|
||||
Please note that you will need to provide environment variables for connecting to the database, redis, aws and so forth.
|
||||
|
||||
For detailed instructions on how to configure and run the Docker container, please refer to the Docker [Docker README](./docker/README.md) in the docker directory.
|
||||
|
||||
## Developer Setup
|
||||
|
||||
### Install Dependencies
|
||||
@ -96,25 +46,15 @@ pnpm i
|
||||
### Setting up the environment
|
||||
|
||||
- Copy the env.example file into .env
|
||||
- Setup google oauth required for auth https://next-auth.js.org/providers/google or Email provider by setting SMTP details
|
||||
- Login to minio console using `splitpro` user and password `password` and [create access keys](http://localhost:9001/access-keys/new-account) and the R2 related env variables
|
||||
- Must: Google Provider
|
||||
- Must: DATABASE_URL
|
||||
```bash
|
||||
pnpm db:dev # init schema
|
||||
```
|
||||
- Option: R2 related
|
||||
|
||||
### Run the app
|
||||
|
||||
```bash
|
||||
pnpm d
|
||||
```
|
||||
|
||||
## Sponsors
|
||||
|
||||
We are grateful for the support of our sponsors.
|
||||
|
||||
### Our Sponsors
|
||||
|
||||
<a href="https://hekuta.net/en" target="_blank">
|
||||
<img src="https://avatars.githubusercontent.com/u/70084358?v=4" alt="hekuta" style="width:60px;height:60px;">
|
||||
</a>
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#oss-apps/split-pro&Date)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "SplitPro",
|
||||
"short_name": "SplitPro",
|
||||
"description": "Split Expenses with your friends for free. SplitPro is an open-source alternative for splitwise",
|
||||
"name": "SplitwiseLocal",
|
||||
"short_name": "SplitwiseLocal",
|
||||
"description": "Split Expenses with your friends for free. SplitwiseLocal is an open-source alternative for splitwise",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/ios/72.png",
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
"display": "standalone",
|
||||
"scope": "/",
|
||||
"start_url": "/balances",
|
||||
"name": "SplitPro",
|
||||
"short_name": "SplitPro",
|
||||
"name": "SplitwiseLocal",
|
||||
"short_name": "SplitwiseLocal",
|
||||
"description": "Split Expenses with your friends for free",
|
||||
"icons": [
|
||||
{
|
||||
|
||||
@ -8,32 +8,32 @@
|
||||
|
||||
|
||||
<url>
|
||||
<loc>https://splitpro.app/</loc>
|
||||
<loc>https://splitwiselocal.app/</loc>
|
||||
<lastmod>2024-04-03T05:23:09+00:00</lastmod>
|
||||
<priority>1.00</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://splitpro.app/blog/need-for-splitwise-alternative</loc>
|
||||
<loc>https://splitwiselocal.app/blog/need-for-splitwise-alternative</loc>
|
||||
<lastmod>2024-04-03T05:23:09+00:00</lastmod>
|
||||
<priority>1</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://splitpro.app/terms</loc>
|
||||
<loc>https://splitwiselocal.app/terms</loc>
|
||||
<lastmod>2024-04-03T05:23:09+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://splitpro.app/privacy</loc>
|
||||
<loc>https://splitwiselocal.app/privacy</loc>
|
||||
<lastmod>2024-04-03T05:23:09+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://splitpro.app/auth/signin</loc>
|
||||
<loc>https://splitwiselocal.app/auth/signin</loc>
|
||||
<lastmod>2024-04-03T05:23:09+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://splitpro.app/balances</loc>
|
||||
<loc>https://splitwiselocal.app/balances</loc>
|
||||
<lastmod>2024-04-03T05:23:09+00:00</lastmod>
|
||||
<priority>0.64</priority>
|
||||
</url>
|
||||
|
||||
@ -432,23 +432,6 @@ export const AddOrEditExpensePage: React.FC<{
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className=" flex w-full justify-center">
|
||||
<Link
|
||||
href="https://github.com/sponsors/KMKoushik"
|
||||
target="_blank"
|
||||
className="mx-auto"
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="text-md justify-between rounded-full border-pink-500 hover:text-foreground/80"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<HeartHandshakeIcon className="h-5 w-5 text-pink-500" />
|
||||
Sponsor us
|
||||
</div>
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -44,7 +44,7 @@ const InstallApp: React.FC = () => {
|
||||
shouldCloseOnAction
|
||||
>
|
||||
<div className="flex flex-col gap-8">
|
||||
<p>You can download SplitPro as a PWA to your home screen</p>
|
||||
<p>You can download SplitwiseLocal as a PWA to your home screen</p>
|
||||
|
||||
<p>
|
||||
If you are using iOS, checkout this{' '}
|
||||
|
||||
@ -35,7 +35,7 @@ const MainLayout: React.FC<MainLayoutProps> = ({ children, actions, hideAppBar,
|
||||
>
|
||||
<nav className="item-center -ml-[170px] hidden w-[170px] px-4 py-4 lg:flex lg:flex-col lg:gap-2 ">
|
||||
<Link href="/balances" className="mb-8 flex items-center gap-2 ">
|
||||
<span className="text-xl font-medium ">SplitPro</span>
|
||||
<span className="text-xl font-medium ">SplitwiseLocal</span>
|
||||
</Link>
|
||||
<NavItemDesktop
|
||||
title="Balances"
|
||||
|
||||
@ -24,11 +24,11 @@ const MyApp: AppType<{ session: Session | null }> = ({
|
||||
return (
|
||||
<main className={clsx(poppins.className, 'h-full')}>
|
||||
<Head>
|
||||
<title>SplitPro: Split Expenses with your friends for free</title>
|
||||
<title>SplitwiseLocal: Split Expenses with your friends for free</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="application-name" content="SplitPro" />
|
||||
<meta name="application-name" content="SplitwiseLocal" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-title" content="SplitPro" />
|
||||
<meta name="apple-mobile-web-app-title" content="SplitwiseLocal" />
|
||||
<meta name="description" content="Split Expenses with your friends for free" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
@ -51,17 +51,17 @@ const MyApp: AppType<{ session: Session | null }> = ({
|
||||
<link rel="shortcut icon" href="/favicon.ico" />
|
||||
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:url" content="https://splitpro.app" />
|
||||
<meta name="twitter:title" content="SplitPro" />
|
||||
<meta name="twitter:url" content="https://splitwiselocal.app" />
|
||||
<meta name="twitter:title" content="SplitwiseLocal" />
|
||||
<meta name="twitter:description" content="Split Expenses with your friends for free" />
|
||||
<meta name="twitter:image" content="https://splitpro.app/og_banner.png" />
|
||||
<meta name="twitter:image" content="https://splitwiselocal.app/og_banner.png" />
|
||||
<meta name="twitter:creator" content="@KM_Koushik_" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="SplitPro" />
|
||||
<meta property="og:title" content="SplitwiseLocal" />
|
||||
<meta property="og:description" content="Split Expenses with your friends for free" />
|
||||
<meta property="og:site_name" content="SplitPro" />
|
||||
<meta property="og:url" content="https://splitpro.app" />
|
||||
<meta property="og:image" content="https://splitpro.app/og_banner.png" />
|
||||
<meta property="og:site_name" content="SplitwiseLocal" />
|
||||
<meta property="og:url" content="https://splitwiselocal.app" />
|
||||
<meta property="og:image" content="https://splitwiselocal.app/og_banner.png" />
|
||||
</Head>
|
||||
<SessionProvider session={session}>
|
||||
<ThemeProvider attribute="class" defaultTheme="dark">
|
||||
|
||||
@ -67,114 +67,6 @@ const AccountPage: NextPageWithUser = ({ user }) => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 flex flex-col gap-4">
|
||||
<Link href="https://twitter.com/KM_Koushik_" target="_blank">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="text-md w-full justify-between px-0 hover:text-foreground/80"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1200 1227"
|
||||
fill="none"
|
||||
className="h-5 w-5 px-1"
|
||||
>
|
||||
<g clip-path="url(#clip0_1_2)">
|
||||
<path
|
||||
d="M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1_2">
|
||||
<rect width="1200" height="1227" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
Follow us on X
|
||||
</div>
|
||||
<ChevronRight className="h-6 w-6 text-gray-500" />
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="https://github.com/oss-apps/split-pro" target="_blank">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="text-md w-full justify-between px-0 hover:text-foreground/80"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<Github className="h-5 w-5 text-gray-200" />
|
||||
Star us on Github
|
||||
</div>
|
||||
<ChevronRight className="h-6 w-6 text-gray-500" />
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="https://github.com/sponsors/KMKoushik" target="_blank">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="text-md w-full justify-between px-0 hover:text-foreground/80"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<HeartHandshakeIcon className="h-5 w-5 text-pink-600" />
|
||||
Sponsor us
|
||||
</div>
|
||||
<ChevronRight className="h-6 w-6 text-gray-500" />
|
||||
</Button>
|
||||
</Link>
|
||||
<SubmitFeedback />
|
||||
<SubscribeNotification />
|
||||
<Link href="https://www.producthunt.com/products/splitpro/reviews/new" target="_blank">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="text-md w-full justify-between px-0 hover:text-foreground/80"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<Star className="h-5 w-5 text-yellow-400" />
|
||||
Write a review
|
||||
</div>
|
||||
<ChevronRight className="h-6 w-6 text-gray-500" />
|
||||
</Button>
|
||||
</Link>
|
||||
<AppDrawer
|
||||
trigger={
|
||||
<div className="flex w-full justify-between px-0 py-2 text-[16px] font-medium text-gray-300 hover:text-foreground/80">
|
||||
<div className="flex items-center gap-4">
|
||||
<Download className="h-5 w-5 text-blue-500" />
|
||||
Download App
|
||||
</div>
|
||||
<ChevronRight className="h-6x w-6 text-gray-500" />
|
||||
</div>
|
||||
}
|
||||
leftAction="Close"
|
||||
title="Download App"
|
||||
className="h-[70vh]"
|
||||
shouldCloseOnAction
|
||||
>
|
||||
<div className="flex flex-col gap-8">
|
||||
<p>You can download SplitPro as a PWA to your home screen</p>
|
||||
|
||||
<p>
|
||||
If you are using iOS, checkout this{' '}
|
||||
<a
|
||||
className="text-cyan-500 underline"
|
||||
href="https://youtube.com/shorts/MQHeLOjr350"
|
||||
target="_blank"
|
||||
>
|
||||
video
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you are using Android, checkout this{' '}
|
||||
<a
|
||||
className="text-cyan-500 underline"
|
||||
href="https://youtube.com/shorts/04n7oKGzgOs"
|
||||
target="_blank"
|
||||
>
|
||||
Video
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</AppDrawer>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="text-md w-full justify-between px-0 hover:text-foreground/80"
|
||||
@ -183,7 +75,7 @@ const AccountPage: NextPageWithUser = ({ user }) => {
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<FileDown className="h-5 w-5 text-teal-500" />
|
||||
Download splitpro data
|
||||
Download SplitwiseLocal data
|
||||
</div>
|
||||
{downloading ? (
|
||||
<LoadingSpinner />
|
||||
|
||||
@ -103,14 +103,14 @@ const Home: NextPage<{ feedbackEmail: string; providers: ClientSafeProvider[] }>
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>SplitPro: Split Expenses with your friends for free</title>
|
||||
<meta name="description" content="SplitPro: Split Expenses with your friends for free" />
|
||||
<title>SplitwiseLocal: Split Expenses with your friends for free</title>
|
||||
<meta name="description" content="SplitwiseLocal: Split Expenses with your friends for free" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<main className="flex h-full flex-col justify-center lg:justify-normal">
|
||||
<div className="flex flex-col items-center lg:mt-20 ">
|
||||
<div className="mb-10 flex items-center gap-4">
|
||||
<p className="text-3xl text-primary">SplitPro</p>
|
||||
<p className="text-3xl text-primary">SplitwiseLocal</p>
|
||||
</div>
|
||||
{providers
|
||||
.filter((provider) => provider.id !== 'email')
|
||||
|
||||
@ -17,19 +17,6 @@ import { NotificationModal } from '~/components/NotificationModal';
|
||||
import { GetServerSideProps } from 'next';
|
||||
|
||||
const BalancePage: NextPageWithUser = () => {
|
||||
function shareWithFriends() {
|
||||
if (navigator.share) {
|
||||
navigator
|
||||
.share({
|
||||
title: 'SplitPro',
|
||||
text: "Check out SplitPro. It's an open source free alternative for Splitwise",
|
||||
url: 'https://splitpro.app',
|
||||
})
|
||||
.then(() => console.log('Successful share'))
|
||||
.catch((error) => console.log('Error sharing', error));
|
||||
}
|
||||
}
|
||||
|
||||
const balanceQuery = api.user.getBalances.useQuery();
|
||||
const showProgress = useEnableAfter(350);
|
||||
|
||||
@ -41,15 +28,6 @@ const BalancePage: NextPageWithUser = () => {
|
||||
</Head>
|
||||
<MainLayout
|
||||
title="Balances"
|
||||
actions={
|
||||
typeof window !== 'undefined' && !!window.navigator?.share ? (
|
||||
<Button variant="ghost" onClick={shareWithFriends}>
|
||||
<ArrowUpOnSquareIcon className="h-6 w-6 " />
|
||||
</Button>
|
||||
) : (
|
||||
<div className="h-6 w-10" />
|
||||
)
|
||||
}
|
||||
>
|
||||
<NotificationModal />
|
||||
<div className="">
|
||||
|
||||
@ -67,7 +67,7 @@ ExpensesPage.auth = true;
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: {
|
||||
storagePublicUrl: env.R2_PUBLIC_URL,
|
||||
storagePublicUrl: env.R2_PUBLIC_URL ?? null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ ExpensesPage.auth = true;
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: {
|
||||
storagePublicUrl: env.R2_PUBLIC_URL,
|
||||
storagePublicUrl: env.R2_PUBLIC_URL ?? null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ ExpensesPage.auth = true;
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: {
|
||||
storagePublicUrl: env.R2_PUBLIC_URL,
|
||||
storagePublicUrl: env.R2_PUBLIC_URL ?? null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -3,15 +3,6 @@ import Link from 'next/link';
|
||||
import { Button } from '~/components/ui/button';
|
||||
import {
|
||||
ArrowRight,
|
||||
Banknote,
|
||||
Bell,
|
||||
FileUp,
|
||||
GitFork,
|
||||
Github,
|
||||
Globe,
|
||||
Import,
|
||||
Split,
|
||||
Users,
|
||||
} from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
import { BackgroundGradient } from '~/components/ui/background-gradient';
|
||||
@ -21,8 +12,8 @@ export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>SplitPro: Split Expenses with your friends for free</title>
|
||||
<meta name="description" content="SplitPro: Split Expenses with your friends for free" />
|
||||
<title>SplitwiseLocal: Split Expenses with your friends for free</title>
|
||||
<meta name="description" content="SplitwiseLocal: Split Expenses with your friends for free" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
{process.env.NODE_ENV === 'production' && (
|
||||
<>
|
||||
@ -41,12 +32,7 @@ export default function Home() {
|
||||
<main className="min-h-screen">
|
||||
<nav className="sticky mx-auto flex max-w-5xl items-center justify-between px-4 py-4 lg:px-0 lg:py-5">
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-2xl font-medium">SplitPro</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-8">
|
||||
<Link href="/blog/need-for-splitwise-alternative">Why?</Link>
|
||||
<Link href="/terms">Terms</Link>
|
||||
<Link href="/privacy">Privacy</Link>
|
||||
<p className="text-2xl font-medium">SplitwiseLocal</p>
|
||||
</div>
|
||||
</nav>
|
||||
<div className="mx-auto mt-20 flex w-full items-start justify-center gap-16 px-4 lg:max-w-5xl lg:px-0 ">
|
||||
@ -73,153 +59,12 @@ export default function Home() {
|
||||
Add Expense <ArrowRight size={15} />{' '}
|
||||
</Button>
|
||||
</Link>
|
||||
<Link
|
||||
href="https://github.com/oss-apps/split-pro"
|
||||
target="_blank"
|
||||
className="mx-auto lg:mx-0"
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="flex w-[200px] items-center gap-2 rounded-full"
|
||||
>
|
||||
<Github size={15} /> Star us on github
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<div className=" mt-40"></div>
|
||||
</div>
|
||||
<div className="mb-20 mt-8 flex justify-center lg:hidden">
|
||||
<MobileScreenShot />
|
||||
</div>
|
||||
<div className=" flex flex-col gap-20 text-center lg:text-left">
|
||||
<p className="text-2xl">Features</p>
|
||||
|
||||
<div className="flex flex-col gap-20 lg:flex-row lg:gap-8">
|
||||
<div className="flex flex-col gap-1 lg:w-1/2">
|
||||
<div className="flex flex-row justify-center gap-1 lg:flex-col">
|
||||
<Users className="h-6 w-6 text-primary" />
|
||||
<p className="text-lg font-medium">Groups and Friends</p>
|
||||
</div>
|
||||
<p className="px-4 text-gray-400 lg:px-0">
|
||||
Can create multiple groups or add balance directly. Everything will be
|
||||
consolidated
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1 lg:w-1/2">
|
||||
<div className="flex flex-row justify-center gap-1 lg:flex-col">
|
||||
<Banknote className="h-6 w-6 text-primary" />
|
||||
<p className="text-lg font-medium">Multiple currencies</p>
|
||||
</div>
|
||||
<p className="px-4 text-gray-400 lg:px-0">
|
||||
Need to add expense with different currency for same user? No problem!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-20 lg:flex-row lg:gap-8">
|
||||
<div className="flex flex-col gap-1 lg:w-1/2">
|
||||
<div className="flex flex-row justify-center gap-1 lg:flex-col">
|
||||
<Split className="h-6 w-6 text-primary" />
|
||||
<p className="text-lg font-medium">Unequal Split</p>
|
||||
</div>
|
||||
<p className="px-4 text-gray-400 lg:px-0">
|
||||
Advanced split options. By shares, percentage or exact amounts.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1 lg:w-1/2">
|
||||
<div className="flex flex-row justify-center gap-1 lg:flex-col">
|
||||
<Globe className="h-6 w-6 text-primary" />
|
||||
<p className="text-lg font-medium">PWA support</p>
|
||||
</div>
|
||||
<p className="px-4 text-gray-400 lg:px-0">
|
||||
Love mobile apps? We got you covered. Install it as a PWA and you won't
|
||||
even notice!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-20 lg:flex-row lg:gap-8">
|
||||
<div className="flex flex-col gap-1 lg:w-1/2">
|
||||
<div className="flex flex-row justify-center gap-1 lg:flex-col">
|
||||
<FileUp className="h-6 w-6 text-primary" />
|
||||
<p className="text-lg font-medium">Upload Receipts</p>
|
||||
</div>
|
||||
<p className="px-4 text-gray-400 lg:px-0">
|
||||
Upload receipts along with the expense
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1 lg:w-1/2">
|
||||
<div className="flex flex-row justify-center gap-1 lg:flex-col">
|
||||
<GitFork className="h-6 w-6 text-primary" />
|
||||
<p className="text-lg font-medium">Open source</p>
|
||||
</div>
|
||||
<p className="px-4 text-gray-400 lg:px-0">
|
||||
Which makes it hard to become evil. Easy to self host
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-20 lg:flex-row lg:gap-8">
|
||||
<div className="flex flex-col gap-1 lg:w-1/2">
|
||||
<div className="flex flex-row justify-center gap-1 lg:flex-col">
|
||||
<Import className="h-6 w-6 text-primary" />
|
||||
<p className="text-lg font-medium">Import from splitwise</p>
|
||||
</div>
|
||||
<p className="px-4 text-gray-400 lg:px-0">
|
||||
Don't have to manually migrate balances. You can import users and groups
|
||||
from splitwise
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 lg:w-1/2">
|
||||
<div className="flex flex-row justify-center gap-1 lg:flex-col">
|
||||
<Bell className="h-6 w-6 text-primary" />
|
||||
<p className="text-lg font-medium">Push notification</p>
|
||||
</div>
|
||||
<p className="px-4 text-gray-400 lg:px-0">
|
||||
Never miss important notifications. Get notified when someone adds an expense or
|
||||
settles up
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-20 mt-24 flex flex-col gap-8 text-center lg:text-left">
|
||||
<a
|
||||
href="https://www.producthunt.com/posts/splitpro?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-splitpro"
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=444717&theme=light"
|
||||
alt="Splitpro - Free drop in replacement  to Splitwise: Fully Open source | Product Hunt"
|
||||
className="mx-auto h-[47px] w-[200px] lg:mx-0"
|
||||
width="200"
|
||||
height="47"
|
||||
/>
|
||||
</a>
|
||||
<div>
|
||||
Built by{' '}
|
||||
<a className=" text-primary" href="https://koushik.dev" target="_blank">
|
||||
KM Koushik
|
||||
</a>
|
||||
{/* <p className="text-gray-400">
|
||||
A product of <a className="underline underline-offset-2">ossapps.dev</a>
|
||||
</p> */}
|
||||
</div>
|
||||
<div className="flex justify-center gap-4 lg:justify-start">
|
||||
<a className="text-primary" href="https://twitter.com/KM_Koushik_" target="_blank">
|
||||
Twitter
|
||||
</a>
|
||||
<a
|
||||
className="text-primary"
|
||||
href="https://github.com/oss-apps/split-pro"
|
||||
target="_blank"
|
||||
>
|
||||
Github
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sticky top-40 hidden shrink-0 lg:flex">
|
||||
<MobileScreenShot />
|
||||
|
||||
@ -10,7 +10,7 @@ const Privacy: NextPage<{ feedbackEmail: string }> = ({ feedbackEmail }) => {
|
||||
<nav className="sticky mx-auto flex max-w-5xl items-center justify-between px-4 py-4 lg:px-0 lg:py-5">
|
||||
<Link href="/">
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-2xl font-medium">SplitPro</p>
|
||||
<p className="text-2xl font-medium">SplitwiseLocal</p>
|
||||
</div>
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
@ -11,7 +11,7 @@ const Terms: NextPage<{ feedbackEmail: string }> = ({ feedbackEmail }) => {
|
||||
<nav className="sticky mx-auto flex max-w-5xl items-center justify-between px-4 py-4 lg:px-0 lg:py-5">
|
||||
<Link href="/">
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-2xl font-medium">SplitPro</p>
|
||||
<p className="text-2xl font-medium">SplitwiseLocal</p>
|
||||
</div>
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
@ -44,9 +44,9 @@ export async function sendSignUpEmail(email: string, token: string, url: string)
|
||||
return true;
|
||||
}
|
||||
|
||||
const subject = 'Sign in to SplitPro';
|
||||
const text = `Hey,\n\nYou can sign in to SplitPro by clicking the below URL:\n${url}\n\nYou can also use this OTP: ${token}\n\nThanks,\nSplitPro Team`;
|
||||
const html = `<p>Hey,</p> <p>You can sign in to SplitPro by clicking the below URL:</p><p><a href="${url}">Sign in to ${host}</a></p><p>You can also use this OTP: <b>${token}</b></p><br /><br /><p>Thanks,</p><br/>SplitPro Team</p>`;
|
||||
const subject = 'Sign in to SplitwiseLocal';
|
||||
const text = `Hey,\n\nYou can sign in to SplitwiseLocal by clicking the below URL:\n${url}\n\nYou can also use this OTP: ${token}\n\nThanks,\nSplitPro Team`;
|
||||
const html = `<p>Hey,</p> <p>You can sign in to SplitwiseLocal by clicking the below URL:</p><p><a href="${url}">Sign in to ${host}</a></p><p>You can also use this OTP: <b>${token}</b></p><br /><br /><p>Thanks,</p><br/>SplitwiseLocal Team</p>`;
|
||||
|
||||
return await sendMail(email, subject, text, html);
|
||||
}
|
||||
@ -63,9 +63,9 @@ export async function sendInviteEmail(email: string, name: string) {
|
||||
return;
|
||||
}
|
||||
|
||||
const subject = 'Invitation to SplitPro';
|
||||
const text = `Hey,\n\nYou have been invited to SplitPro by ${name}. It's a completely open source free alternative to splitwise. You can sign in to SplitPro by clicking the below URL:\n${env.NEXTAUTH_URL}\n\nThanks,\nSplitPro Team`;
|
||||
const html = `<p>Hey,</p> <p>You have been invited to SplitPro by ${name}. It's a completely open source free alternative to splitwise. You can sign in to SplitPro by clicking the below URL:</p><p><a href="${env.NEXTAUTH_URL}">Sign in to ${host}</a></p><br><p>Thanks,<br/>SplitPro Team</p>`;
|
||||
const subject = 'Invitation to SplitwiseLocal';
|
||||
const text = `Hey,\n\nYou have been invited to SplitwiseLocal by ${name}. It's a completely open source free alternative to splitwise. You can sign in to SplitwiseLocal by clicking the below URL:\n${env.NEXTAUTH_URL}\n\nThanks,\nSplitPro Team`;
|
||||
const html = `<p>Hey,</p> <p>You have been invited to SplitwiseLocal by ${name}. It's a completely open source free alternative to splitwise. You can sign in to SplitwiseLocal by clicking the below URL:</p><p><a href="${env.NEXTAUTH_URL}">Sign in to ${host}</a></p><br><p>Thanks,<br/>SplitwiseLocal Team</p>`;
|
||||
|
||||
await sendMail(email, subject, text, html);
|
||||
}
|
||||
@ -75,7 +75,7 @@ export async function sendFeedbackEmail(feedback: string, user: User) {
|
||||
|
||||
if (!env.FEEDBACK_EMAIL) return;
|
||||
|
||||
const subject = `Feedback received on SplitPro from ${user.name}`;
|
||||
const subject = `Feedback received on SplitwiseLocal from ${user.name}`;
|
||||
const text = `Feedback created by ${user.name} :\n\nFeedback: ${feedback}\n\nemail: ${user.email}`;
|
||||
|
||||
await sendMail(env.FEEDBACK_EMAIL, subject, text, text, user.email ?? undefined);
|
||||
|
||||
@ -8,7 +8,7 @@ import { Separator } from '~/components/ui/separator';
|
||||
const config = {
|
||||
footer: (
|
||||
<div className="mt-20 flex items-center justify-center gap-4">
|
||||
<Link href="https://splitpro.app/balances" target="_blank">
|
||||
<Link href="https://splitwiselocal.app/balances" target="_blank">
|
||||
App
|
||||
</Link>
|
||||
<Separator orientation="vertical" className="h-5" />
|
||||
@ -16,7 +16,7 @@ const config = {
|
||||
Github
|
||||
</Link>
|
||||
<Separator orientation="vertical" className="h-5" />
|
||||
<Link href="https://www.producthunt.com/products/splitpro/reviews/new" target="_blank">
|
||||
<Link href="https://www.producthunt.com/products/splitwiselocal/reviews/new" target="_blank">
|
||||
Product Hunt
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user