Skip to content
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
3 changes: 1 addition & 2 deletions public/locales/de/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
"messages": {
"import_success": "Import erfolgreich"
},
"no_file_chosen": "Keine Datei ausgewählt",
"note": "Hinweis: Es werden derzeit nur Freunde und Gruppen importiert. Transaktionen werden nicht importiert. Wir arbeiten daran."
"no_file_chosen": "Keine Datei ausgewählt"
},
"logout": "Abmelden",
"messages": {
Expand Down
4 changes: 2 additions & 2 deletions public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
"messages": {
"import_success": "Import successful"
},
"no_file_chosen": "No file chosen",
"note": "Note: It currently only supports importing friends and groups. It will not import transactions. We are working on it."
"selected_expenses": "Selected expenses",
"no_file_chosen": "No file chosen"
},
"logout": "Logout",
"messages": {
Expand Down
3 changes: 1 addition & 2 deletions public/locales/es-AR/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
"messages": {
"import_success": "Importación exitosa"
},
"no_file_chosen": "Ningún archivo seleccionado",
"note": "Nota: Actualmente solo soporta la importación de amigos y grupos. No importará transacciones. Estamos trabajando en ello."
"no_file_chosen": "Ningún archivo seleccionado"
},
"logout": "Cerrar sesión",
"messages": {
Expand Down
3 changes: 1 addition & 2 deletions public/locales/es-MX/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
"messages": {
"import_success": "Importación exitosa"
},
"no_file_chosen": "Ningún archivo seleccionado",
"note": "Nota: Actualmente solo soporta la importación de amigos y grupos. No importará transacciones. Estamos trabajando en ello."
"no_file_chosen": "Ningún archivo seleccionado"
},
"logout": "Cerrar sesión",
"notifications": {
Expand Down
3 changes: 1 addition & 2 deletions public/locales/fr/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
"messages": {
"import_success": "L'import est un succès"
},
"no_file_chosen": "Aucun fichier choisi",
"note": "Note : l'import ne fonctionne actuellement que pour les ami⋅es et les groupes, mais pas pour les transactions. On y travaille !"
"no_file_chosen": "Aucun fichier choisi"
},
"logout": "Déconnexion",
"messages": {
Expand Down
3 changes: 1 addition & 2 deletions public/locales/it/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
"messages": {
"import_success": "Importazione riuscita"
},
"no_file_chosen": "Nessun file scelto",
"note": "Nota: al momento supporta solo l'importazione di amici e gruppi. Non importerà transazioni. Ci stiamo lavorando."
"no_file_chosen": "Nessun file scelto"
},
"logout": "Esci",
"messages": {
Expand Down
3 changes: 1 addition & 2 deletions public/locales/pl/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
"messages": {
"import_success": "Import zakończony pomyślnie"
},
"no_file_chosen": "Nie wybrano pliku",
"note": "Uwaga: Obecnie obsługuje tylko importowanie znajomych i grup. Nie importuje transakcji. Pracujemy nad tym."
"no_file_chosen": "Nie wybrano pliku"
},
"logout": "Wyloguj",
"messages": {
Expand Down
3 changes: 1 addition & 2 deletions public/locales/pt-BR/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
"messages": {
"import_success": "Importação realizada"
},
"no_file_chosen": "Nenhum arquivo selecionado",
"note": "Aviso: Atualmente só é possível importar amigos e grupos. Transações não serão importadas. Estamos trabalhando nisso."
"no_file_chosen": "Nenhum arquivo selecionado"
},
"logout": "Fazer logout",
"messages": {
Expand Down
3 changes: 1 addition & 2 deletions public/locales/pt-PT/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
"messages": {
"import_success": "Importar com sucesso"
},
"no_file_chosen": "Ficheiro não selecionado",
"note": "Nota: Ainda só temos suporte a importar amigos e grupos. A transações não serão importadas. Estamos a trabalhar nisso."
"no_file_chosen": "Ficheiro não selecionado"
},
"logout": "Terminar Sessão",
"messages": {
Expand Down
3 changes: 1 addition & 2 deletions public/locales/sv/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
"messages": {
"import_success": "Import lyckades"
},
"no_file_chosen": "Ingen fil vald",
"note": "Notera: Vi stödjer för närvarande endast import av vänner och grupper. Transaktioner kommer inte importeras. Vi arbetar på det."
"no_file_chosen": "Ingen fil vald"
},
"logout": "Logga ut",
"messages": {
Expand Down
9 changes: 9 additions & 0 deletions src/pages/api/trpc/[trpc].ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,12 @@ export default createNextApiHandler({
}
: undefined,
});

export const config = {
api: {
bodyParser: {
sizeLimit: '20mb',
},
responseLimit: '20mb',
},
};
61 changes: 53 additions & 8 deletions src/pages/import-splitwise.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DownloadCloud } from 'lucide-react';
import Head from 'next/head';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { toast } from 'sonner';
import { useTranslation } from 'next-i18next';
import MainLayout from '~/components/Layout/MainLayout';
Expand All @@ -12,16 +12,24 @@ import { Checkbox } from '~/components/ui/checkbox';
import { Input } from '~/components/ui/input';
import { Separator } from '~/components/ui/separator';
import { LoadingSpinner } from '~/components/ui/spinner';
import { type NextPageWithUser, type SplitwiseGroup, type SplitwiseUser } from '~/types';
import {
type NextPageWithUser,
type SplitwiseExpense,
type SplitwiseGroup,
type SplitwiseUserWithBalance,
} from '~/types';
import { api } from '~/utils/api';
import { withI18nStaticProps } from '~/utils/i18n/server';
import { set } from 'date-fns';

const ImportSpliwisePage: NextPageWithUser = () => {
const { t } = useTranslation();
const [usersWithBalance, setUsersWithBalance] = useState<SplitwiseUser[]>([]);
const [usersWithBalance, setUsersWithBalance] = useState<SplitwiseUserWithBalance[]>([]);
const [groups, setGroups] = useState<SplitwiseGroup[]>([]);
const [expenses, setExpenses] = useState<SplitwiseExpense[]>([]);
const [selectedUsers, setSelectedUsers] = useState<Record<string, boolean>>({});
const [selectedGroups, setSelectedGroups] = useState<Record<string, boolean>>({});
const [selectedExpenses, setSelectedExpenses] = useState<Record<string, boolean>>({});
const [uploadedFile, setUploadedFile] = useState<File | null>(null);

const router = useRouter();
Expand All @@ -39,11 +47,11 @@ const ImportSpliwisePage: NextPageWithUser = () => {

try {
const json = JSON.parse(await file.text()) as Record<string, unknown>;
const friendsWithOutStandingBalance: SplitwiseUser[] = [];
const friendsWithOutStandingBalance: SplitwiseUserWithBalance[] = [];
for (const friend of json.friends as Record<string, unknown>[]) {
const balance = friend.balance as { currency_code: string; amount: string }[];
if (balance.length && 'confirmed' === friend.registration_status) {
friendsWithOutStandingBalance.push(friend as unknown as SplitwiseUser);
friendsWithOutStandingBalance.push(friend as unknown as SplitwiseUserWithBalance);
}
}

Expand Down Expand Up @@ -72,19 +80,47 @@ const ImportSpliwisePage: NextPageWithUser = () => {
{} as Record<string, boolean>,
),
);

const _expenses = (json.expenses as SplitwiseExpense[]).filter((e) => !e.deleted_at);

setExpenses(_expenses);
} catch (e) {
console.error(e);
toast.error(t('errors.import_failed'));
}
};

useEffect(() => {
if (!expenses || !expenses.length) {
setSelectedExpenses({});
return;
}

setSelectedExpenses(
expenses.reduce(
(acc, expense) => {
const isUserSelected = expense.users.some((user) => selectedUsers[user.user_id]);
const isGroupSelected = expense.group_id ? selectedGroups[expense.group_id] : false;

if (isUserSelected || isGroupSelected) {
acc[expense.id] = true;
}

return acc;
},
{} as Record<string, boolean>,
),
);
}, [expenses, selectedUsers, selectedGroups]);

const importMutation = api.user.importUsersFromSplitWise.useMutation();

function onImport() {
importMutation.mutate(
{
usersWithBalance: usersWithBalance.filter((user) => selectedUsers[user.id]),
groups: groups.filter((group) => selectedGroups[group.id]),
expenses: expenses.filter((expense) => selectedExpenses[expense.id]),
},
{
onSuccess: () => {
Expand Down Expand Up @@ -155,9 +191,6 @@ const ImportSpliwisePage: NextPageWithUser = () => {
{importMutation.isPending ? <LoadingSpinner /> : t('actions.import')}
</Button>
</div>
<div className="mt-4 text-sm text-gray-400">
{t('account.import_from_splitwise_details.note')}
</div>

{uploadedFile ? (
<>
Expand Down Expand Up @@ -232,6 +265,18 @@ const ImportSpliwisePage: NextPageWithUser = () => {
))}
</div>
) : null}
<div className="mt-8 flex flex-col gap-3">
<div className="flex justify-between gap-3">
<div className="flex items-center gap-2">
<div className="flex font-semibold">
<p>{t('account.import_from_splitwise_details.selected_expenses')}</p>
</div>
</div>
<div className="flex shrink-0 flex-wrap justify-end gap-1">
{Object.keys(selectedExpenses).length}
</div>
</div>
</div>
</>
) : (
<div className="mt-20 flex flex-col items-center justify-center gap-4">
Expand Down
16 changes: 14 additions & 2 deletions src/server/api/routers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ import { env } from '~/env';
import { createTRPCRouter, protectedProcedure } from '~/server/api/trpc';
import { db } from '~/server/db';
import { sendFeedbackEmail, sendInviteEmail } from '~/server/mailer';
import { SplitwiseGroupSchema, SplitwiseUserSchema } from '~/types';
import {
SplitwiseExpenseSchema,
SplitwiseGroupSchema,
SplitwiseUserWithBalanceSchema,
} from '~/types';

// import { sendExpensePushNotification } from '../services/notificationService';
import {
getCompleteFriendsDetails,
getCompleteGroupDetails,
importExpenseFromSplitwise,
importGroupFromSplitwise,
importUserBalanceFromSplitWise,
} from '../services/splitService';
Expand Down Expand Up @@ -239,13 +244,20 @@ export const userRouter = createTRPCRouter({
importUsersFromSplitWise: protectedProcedure
.input(
z.object({
usersWithBalance: z.array(SplitwiseUserSchema),
usersWithBalance: z.array(SplitwiseUserWithBalanceSchema),
groups: z.array(SplitwiseGroupSchema),
expenses: z.array(SplitwiseExpenseSchema),
}),
)
.mutation(async ({ input, ctx }) => {
await importUserBalanceFromSplitWise(ctx.session.user.id, input.usersWithBalance);
await importGroupFromSplitwise(ctx.session.user.id, input.groups);
await importExpenseFromSplitwise(
ctx.session.user.id,
input.expenses,
input.usersWithBalance,
input.groups,
);
}),

getWebPushPublicKey: protectedProcedure.query(() => env.WEB_PUSH_PUBLIC_KEY ?? ''),
Expand Down
Loading