# Meetly -- a Telegram mini app
Slogan - Appointments made easy
Description - Meet anyone you want with Meetly - the app that makes booking appointments easy.
f
Logo link: https://looka.com/editor/156460361
Domain names:
- getmeet.ly - 75 USD
- meetly.link - 41.3 USD
- meetly.cc - 6 USD
---
Фича №1: Создать ссылку для бронирования
Сценарий 1
- Открывается страница https://meetly.cc/new (как webApp)
- Пользователь вводит:
- date range
- X days into the future
- dateFrom & dateTo
- Indefinitely into the future
- duration
- hours and minutes
- schedule
- working hours per day
- user's timezone
- Нажимает Создать
- создается Link { id: link-id, userId: ..., dateRange: ..., duration: ..., schedule: ..., timezone: ... }
---
- 2 вида ссылок
- https://t.me/meetly_bot/app?startapp=l_%link-id%
- https://go.meetly.cc/link-id (редирект на direct link)
---
Фича №2: Открыть ссылку и забронировать слот
- Пользователь выбирает слот
- Указывает свой email
- Отправляет запрос
- создается Appointment { id, linkId: ..., userId: ..., email: ..., timezone: ... }
- Хост получает нотификацию о новом запросе
---
Фича №3: Подтверждение запроса
- Хост открывает уведомление в чате с ботом
-
---
## TODO
- [x] - встроить telegram.js на страницу
- [x] - детекция tgUserId на странице (пробросить из telegram.js)
- [x] - поддержать роутинг по deeplink
- с linkId -> на страницу createNewAppointment
- иначе -> на страницу createNewLink
- [x] - отправка уведомления хосту при создании Appointment
- добавления поля isApproved в Appointment
- обновляем уведомление при апруве
- isApproved=true
- шлем уведомление requestingUserId
- [x] - предсоздание User в базе
- add firstName, username
- [x] - страница создания ссылки
- [..] - стилизация обеих страниц (DaisyUI)
~~- вынести timezone selector в правый верхний угол~~
- [x] - интеграция кнопок MainButton / BackButton
- [..] - **страница создания встречи**
- [x] - XX добавить в шапку "Book an appointment with Ivan Ivanov" (**useEnsureLink**)
- [x] - открываем введение каждого поля поочередно, чтобы в фокусе всегде был только один инпут (timezone, date, timeSlot, email)
- [x] - XX success screen после создания appointment
- https://www.npmjs.com/package/react-confetti
- [x] - XX link not found case
- [..] - **страница создания ссылки**
- [x] - XX шапка по стадиям с описаниями
- [x] - XXX поддержать нерабочие дни
- [x] - открываем введение каждого поля поочередно, чтобы в фокусе всегде был только один инпут (timezone, duration, schedule)
- [x] - XX success screen после создания link
- https://www.npmjs.com/package/react-confetti
- [x] - XXX фикс цветов calendar
- [x] - XXX фикс цветов timezone selector
- [x] - XX фикс цветов main button (color, textColor)
- [x] - XXXX ??? welcome screen
- [x] показываем ссылку если есть (url, duration, schedule) или кнопку "Создать"
~~- [ ] react-icons~~
- [x] - XX присылать созданную ссылку ботом в чат
- [x] - XX добавить информацию о человеке и встрече в уведомления
- [x] - XXXXXX написать Readme
- [x] - XXX тестирование на разных клиентах
- [x] - XXXXX прогнать через light house, FCP/LCP, web-vitals метрики
- [x] - X remove Eruda
- [x] - XX remove TODOs & console.log()
## Доп фичи
- обернуть Client Components в Suspense
- requests auto-rejection by ttl
- предложить другое время
- поддержать dateRange для модели Link
~~- link id picker~~
- https://go.meetly.cc/link-id redirects to https://t.me/meetly_bot/app?startapp=l_%link-id%
- disable completely booked days в Calendar
- авторизация [через Google] + NextAuth.js https://blog.logrocket.com/using-next-js-route-handlers/#creating-secured-routes
- Connect Google Account
- Auto-add to Google Calendar
- Авторизация на meetly.cc через Telegram
- https://tanstack.com/query/latest/docs/react/guides/window-focus-refetching
- i18n
- Captcha
~~- requester не может создать несколько запросов на одно и то же время на разных ссылках~~
- add Sentry
~~- add HttpError~~
- WebApp.CloudStorage для Schedule
- написать интеграционные тесты
- создание ссылки
- запрос на встречу
## Useful links
- https://tkdodo.eu/blog/react-query-and-forms
- CORS https://blog.logrocket.com/using-cors-next-js-handle-cross-origin-requests/#enabling-cors-all-api-routes
- How to Deploy Grammy to Vercel https://github.com/grammyjs/examples/tree/main/setups/next-node
- useQuery invalidation https://tanstack.com/query/latest/docs/react/guides/query-invalidation
---
# Meetly
Данный репозиторий представляет из себя реализацию Telegram Mini Apps сервиса — Meetly, который является аналогом популярного сервиса [Calendly](https://calendly.com).
Meetly — это [Telegram бот](https://t.me/meetly_bot) + [Mini App](https://t.me/meetly_bot/app), который позволяет создать персональную ссылку и использовать ее для приема запросов на встречи.
## Описание бизнес-логики
Каждый пользователь может иметь единственную ссылку. При повторном создании ссылки она будет обновлена с предоставленным расписанием и интервалом.
**Ссылка для отправки запросов**
Созданная ссылка содержит в себе:
- рабочие часы на каждый день недели
- длительность отрезка времени бронирования
- таймзону в которой находится пользователь создавший ссылку
**Запрос на бронь времени**
- каждый запрос содержит email пользователя, отправившего запрос
- может быть подтвержден или отклонен пользователем создавшим ссылку (в результате ботом будут отпрвлены соответствующие уведомления)
### Features
- создание ссылки
- любой пользователь Telegram может создать персональную ссылку
- за ссылкой закрепляется расписание пользователя и длительность отрезка времени бронь
- отправка запроса на бронь
- любой пользователь Telegram, которой перешел по уже созданной ссылке, попадает в интерфейс выбора даты и времени
- доступные отрезки для бронирования отображаются в часовом поясе пользователя, отправляющего запрос
- уведомления в боте
- уведомление о полученном запросе на бронь
- уведомление о подтвержденном / отклоненном запросе
- уведомление о создании / обновлении ссылки для броней
- запрос персональной ссылки через команду /link
- в ответ бот пришлет уже созданную ссылку
### Use-cases
**Отправка запроса на бронь**
Для того, чтобы отправить запрос на бронь времени человека X, нужно запросить у него его персональную ссылку и перейти по ней внутри Telegram. Далее в открывшемся UI выбрать подходящие дату и время и указать email.
**Создание персональной ссылки для получения запросов**
Для того, чтобы предоставить доступ к свободным отрезками времени в своем расписании, необходимо зайти на [страницу создания ссылки](https://t.me/meetly_bot/app?startapp=new), ввести в расписание рабочание дни и часы, а также длительность отрезка, на который будет бронироваться время.
## Техническая реализация
Проект реализован на базе [Next.js](https://nextjs.org/) framework (v14). С его помощью как отдаются клиентские страницы, так и обрабатываются запросы в API.
Список специфичных инструментов и технологий использованных на сервере:
- PostgreSQL + [Prisma](https://www.prisma.io/) - для работы с данными
- [grammY](https://grammy.dev/) - для взаимодействия с Telegram Bots API
Для реализации современного, адаптивного клиентского интерфейса использовались:
- [react-query](https://tanstack.com/query/v3/)
- [react-hook-form](https://react-hook-form.com/)
- [react-day-picker](https://react-day-picker.js.org/)
- [react-timezone-select](https://github.com/ndom91/react-timezone-select)
- a также [Tailwind CSS](https://tailwindcss.com/) вместе с [daisyUI](https://daisyui.com/)
В качестве инфраструктуры для deployment решения был выбран популярный cloud-oriented сервис [Vercel](https://vercel.com/).
### Структура кода
- `/app/layout.tsx` - точка входа в клиентское приложение
- `/app/page.tsx` - основная SSR страница
- `/app/api/**/route.ts` - файлы с реализациями обработчикой CRUD запросов к основным сущностям
- `/app/api/webhook/route.ts` - webhook для получения обновлений от Telegram Bots API
- `/components/*` - реализация обших клиентских компонентов
- `/components/CreateNewAppointment/*` - компоненты реализующие логику отправки запроса на бронь
- `/components/CreateNewLink/*` - компоненты реализующие логику создания и обновления ссылки
- `/components/MainPage/index.tsx` - реализация компонента MainPageComponent, который является точкой входа в клиентском UI
- `/components/WelcomePage/*` - реализация страницы, которая открывается при нажатии кнопки [Menu](https://t.me/meetly_bot/app)
- `/lib/models/*` - типы описывающие все сущности
- `/lib/services/*` - бизнес-логика
- `/lib/bot.ts` - реализация Telegram бота [@meetly_bot](https://t.me/meetly_bot)
- `/prisma/schema.prisma` - описание DB сущностей и их отношений
## Ссылки
- https://t.me/meetly_bot - Telegram бот
- https://t.me/meetly_bot/app - Telegram Mini App