Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AMB-156] refactor: contacts and chat features #97

Merged
merged 3 commits into from
Nov 14, 2024
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
17 changes: 17 additions & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
{
"App": {
"Contacts": {
"add-contact": "Add a contact to start sending them messages or money.",
"address": "Address",
"create": "Create",
"input": "Input the MIBAN Code or Lightning Address from the new contact.",
"loading": "Loading...",
"locked": "Messages Locked",
"max": "Max",
"message": "Message",
"min": "Min",
"new-contact": "New Contact",
"no-pay": "Pay Not Supported",
"no-support": "Messages Not Supported",
"none": "No contacts found.",
"pay": "Pay",
"search": "Search"
},
"Dashboard": {
"asset": "An asset in your wallet.",
"buy": "Buy",
Expand Down
17 changes: 17 additions & 0 deletions messages/es.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
{
"App": {
"Contacts": {
"add-contact": "Agrega un contacto para empezar a enviarle mensajes o dinero.",
"address": "Dirección",
"create": "Crear",
"input": "Introduce el código MIBAN o la dirección Lightning del nuevo contacto.",
"loading": "Cargando...",
"locked": "Mensajes bloqueados",
"max": "Max",
"message": "Mensaje",
"min": "Min",
"new-contact": "Nuevo contacto",
"no-pay": "Pago no soportado",
"no-support": "Mensajes no soportados",
"none": "No se encontraron contactos.",
"pay": "Pagar",
"search": "Buscar"
},
"Dashboard": {
"asset": "Un activo en tu billetera.",
"buy": "Comprar",
Expand Down
24 changes: 12 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/app/(events)/(access)/(layout)/contacts/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Contacts } from '@/views/contacts/Contacts';

export default function Page() {
return <Contacts />;
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { cookies } from 'next/headers';

import { EventHandler } from '@/components/events/Events';
import { Contacts } from '@/views/contacts/Contacts';

export default function Page() {
export default function Layout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const eventsUrl = process.env.EVENTS_URL;

const cookieStore = cookies();
Expand All @@ -14,7 +17,7 @@ export default function Page() {
{accessToken && eventsUrl ? (
<EventHandler accessToken={accessToken} eventsUrl={eventsUrl} />
) : null}
<Contacts />
{children}
</>
);
}
2 changes: 1 addition & 1 deletion src/hooks/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const useSendMessage = (cbk: () => void) => {
if (error) {
const messages = handleApolloError(error as ApolloError);
toast({
variant: 'default',
variant: 'destructive',
title: 'Unable to send message.',
description: messages.join(', '),
});
Expand Down
4 changes: 0 additions & 4 deletions src/stores/contacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,12 @@ export type PaymentOption = {
};

type ChatState = {
currentChatBox: string;
currentPaymentOption: PaymentOption | undefined;
setCurrentChatBox: (type: string) => void;
setCurrentPaymentOption: (option: PaymentOption | undefined) => void;
};

export const useChat = create<ChatState>()(set => ({
currentChatBox: 'message',
currentPaymentOption: undefined,
setCurrentChatBox: (type: string) => set({ currentChatBox: type }),
setCurrentPaymentOption: (option: PaymentOption | undefined) =>
set({ currentPaymentOption: option }),
}));
162 changes: 66 additions & 96 deletions src/views/contacts/AddContact.tsx
Original file line number Diff line number Diff line change
@@ -1,75 +1,54 @@
'use client';

import { zodResolver } from '@hookform/resolvers/zod';
import { Loader2 } from 'lucide-react';
import { Dispatch, FC, SetStateAction } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';

import { Button } from '@/components/ui/button';
import {
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { useTranslations } from 'next-intl';
import { Dispatch, FC, SetStateAction, useEffect, useState } from 'react';

import { Button } from '@/components/ui/button-v2';
import { Input } from '@/components/ui/input';
import { useToast } from '@/components/ui/use-toast';
import { useCreateContactMutation } from '@/graphql/mutations/__generated__/contact.generated';
import { GetWalletContactsDocument } from '@/graphql/queries/__generated__/contacts.generated';
import { useContactStore } from '@/stores/contacts';
import { handleApolloError } from '@/utils/error';

const formSchema = z.object({
money_address: z.string().min(1, {
message:
'A MIBAN Code or Lightning Address is required to create a new contact.',
}),
});

export const AddContact: FC<{
walletId: string;
setOpenDialog: Dispatch<SetStateAction<boolean>>;
}> = ({ walletId, setOpenDialog }) => {
const setContact = useContactStore(s => s.setCurrentContact);

openAdd: boolean;
setOpenAdd: Dispatch<SetStateAction<boolean>>;
}> = ({ walletId, openAdd, setOpenAdd }) => {
const t = useTranslations();
const { toast } = useToast();

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
money_address: '',
},
});
const [address, setAddress] = useState('');

useEffect(() => {
if (!openAdd) {
setAddress('');
}
}, [openAdd]);

const setContact = useContactStore(s => s.setCurrentContact);

const [create, { loading }] = useCreateContactMutation({
onCompleted: data => {
setOpenDialog(false);
setOpenAdd(false);

toast({
variant: 'default',
title: 'Contact Added',
description: 'New contact has been added successfully.',
});

form.reset();
const { id, money_address } = data.contacts.create;

const [user, domain] = data.contacts.create.money_address.split('@');

setContact({
id: data.contacts.create.id,
id,
user,
domain,
address: data.contacts.create.money_address,
address: money_address,
});
},
onError: err => {
Expand All @@ -86,60 +65,51 @@ export const AddContact: FC<{
],
});

const handleSubmit = async (formData: z.infer<typeof formSchema>) => {
create({
variables: {
input: {
wallet_id: walletId,
money_address: formData.money_address,
},
},
});
};

return (
<DialogContent className="mt-4">
<DialogHeader>
<DialogTitle>New Contact</DialogTitle>
<DialogDescription>
Add a contact to start sending them messages or money.
</DialogDescription>
</DialogHeader>

<Form {...form}>
<form
onSubmit={form.handleSubmit(handleSubmit)}
className="w-full space-y-6"
>
<FormField
control={form.control}
name="money_address"
render={({ field }) => (
<FormItem>
<FormLabel>Address</FormLabel>
<FormControl>
<Input
type="money_address"
placeholder="[email protected]"
autoComplete="off"
{...field}
/>
</FormControl>
<FormMessage />
<FormDescription>
Input the MIBAN Code or Lightning Address from the new
contact.
</FormDescription>
</FormItem>
)}
/>

<Button type="submit" disabled={loading}>
{loading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : null}
Create
</Button>
</form>
</Form>
</DialogContent>
<div>
<p className="mb-4 text-2xl font-semibold">
{t('App.Contacts.new-contact')}
</p>

<p className="mb-6 text-sm font-medium text-slate-600 dark:text-neutral-400">
{t('App.Contacts.add-contact')}
</p>

<label htmlFor="address" className="mb-2 block font-semibold">
{t('App.Contacts.address')}
</label>

<Input
id="address"
type="text"
value={address}
onChange={e => setAddress(e.target.value)}
disabled={loading}
/>

<p className="mt-2 text-sm text-slate-600 dark:text-neutral-400">
{t('App.Contacts.input')}
</p>

<Button
onClick={() => {
create({
variables: {
input: {
wallet_id: walletId,
money_address: address,
},
},
});
}}
disabled={!address || loading}
className="mt-4 flex w-full items-center justify-center"
>
{loading ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin text-black" />
) : null}
{t('App.Contacts.create')}
</Button>
</div>
);
};
Loading
Loading