Skip to content

Commit

Permalink
Add download splitpro data (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
KMKoushik authored Mar 27, 2024
1 parent 79041b2 commit ab3125b
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 3 deletions.
36 changes: 35 additions & 1 deletion src/pages/account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import MainLayout from '~/components/Layout/MainLayout';
import { Button } from '~/components/ui/button';
import Link from 'next/link';
import { UserAvatar } from '~/components/ui/avatar';
import { Bell, ChevronRight, Download, Github, Star } from 'lucide-react';
import { Bell, ChevronRight, Download, FileDown, Github, Star } from 'lucide-react';
import { signOut } from 'next-auth/react';
import { AppDrawer } from '~/components/ui/drawer';
import { SubmitFeedback } from '~/components/Account/SubmitFeedback';
Expand All @@ -13,9 +13,27 @@ import { type NextPageWithUser } from '~/types';
import { toast } from 'sonner';
import { env } from '~/env';
import { SubscribeNotification } from '~/components/Account/SubscribeNotification';
import { useState } from 'react';
import { LoadingSpinner } from '~/components/ui/spinner';

const AccountPage: NextPageWithUser = ({ user }) => {
const userQuery = api.user.me.useQuery();
const downloadQuery = api.user.downloadData.useMutation();

const [downloading, setDownloading] = useState(false);

async function downloadData() {
setDownloading(true);
const data = await downloadQuery.mutateAsync();
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'splitpro_data.json';
link.click();
URL.revokeObjectURL(url);
setDownloading(false);
}

return (
<>
Expand Down Expand Up @@ -136,6 +154,22 @@ const AccountPage: NextPageWithUser = ({ user }) => {
</p>
</div>
</AppDrawer>
<Button
variant="ghost"
className="text-md w-full justify-between px-0 hover:text-foreground/80"
onClick={downloadData}
disabled={downloading}
>
<div className="flex items-center gap-4">
<FileDown className="h-5 w-5 text-teal-500" />
Download splitpro data
</div>
{downloading ? (
<LoadingSpinner />
) : (
<ChevronRight className="h-6 w-6 text-gray-500" />
)}
</Button>
</div>

<div className="mt-20 flex justify-center">
Expand Down
19 changes: 17 additions & 2 deletions src/server/api/routers/user.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { SplitType } from '@prisma/client';
import { type Balance, SplitType } from '@prisma/client';
import { boolean, z } from 'zod';
import { createTRPCRouter, protectedProcedure } from '~/server/api/trpc';
import { db } from '~/server/db';
import { addUserExpense, deleteExpense } from '../services/splitService';
import {
addUserExpense,
deleteExpense,
getCompleteFriendsDetails,
getCompleteGroupDetails,
} from '../services/splitService';
import { TRPCError } from '@trpc/server';
import { randomUUID } from 'crypto';
import { getDocumentUploadUrl } from '~/server/storage';
import { FILE_SIZE_LIMIT } from '~/lib/constants';
import { sendFeedbackEmail } from '~/server/mailer';
import { pushNotification } from '~/server/notification';
import { toFixedNumber, toUIString } from '~/utils/numbers';

export const userRouter = createTRPCRouter({
me: protectedProcedure.query(async ({ ctx }) => {
Expand Down Expand Up @@ -441,4 +447,13 @@ export const userRouter = createTRPCRouter({
},
});
}),

downloadData: protectedProcedure.mutation(async ({ ctx }) => {
const user = ctx.session.user;

const friends = await getCompleteFriendsDetails(user.id);
const groups = await getCompleteGroupDetails(user.id);

return { friends, groups };
}),
});
64 changes: 64 additions & 0 deletions src/server/api/services/splitService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,3 +551,67 @@ export async function sendExpensePushNotification(expenseId: string) {

await Promise.all(pushNotifications);
}

export async function getCompleteFriendsDetails(userId: number) {
const balances = await db.balance.findMany({
where: {
userId,
},
include: {
friend: true,
},
});

const friends = balances.reduce(
(acc, balance) => {
const friendId = balance.friendId;
if (!acc[friendId]) {
acc[friendId] = {
balances: [],
id: balance.friendId,
email: balance.friend.email,
name: balance.friend.name,
};
}

if (balance.amount !== 0) {
acc[friendId]?.balances.push({
currency: balance.currency,
amount:
balance.amount > 0 ? toFixedNumber(balance.amount) : toFixedNumber(balance.amount),
});
}

return acc;
},
{} as Record<
number,
{
id: number;
email?: string | null;
name?: string | null;
balances: { currency: string; amount: number }[];
}
>,
);

return friends;
}

export async function getCompleteGroupDetails(userId: number) {
const groups = await db.group.findMany({
where: {
groupUsers: {
some: {
userId,
},
},
},
include: {
groupUsers: true,
groupBalances: true,
},
});

return groups;
}

0 comments on commit ab3125b

Please sign in to comment.