Skip to content

Commit

Permalink
Merge pull request #10 from QuantGeekDev/feature/contact-sales
Browse files Browse the repository at this point in the history
Feature/contact sales
  • Loading branch information
QuantGeekDev authored Jan 5, 2024
2 parents 7d19abd + fdc0497 commit 512681d
Show file tree
Hide file tree
Showing 14 changed files with 71 additions and 61 deletions.
42 changes: 0 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

Intenteded to display real estate properties concisely via a Telegram Bot


[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=QuantGeekDev_PropertyGram-telegram-bot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=QuantGeekDev_PropertyGram-telegram-bot)


## Features

- Built with TypeScript for static typing and enhanced code quality.
Expand All @@ -14,50 +12,10 @@ Intenteded to display real estate properties concisely via a Telegram Bot
- Easy-to-use script commands for compiling, starting, and managing the bot process.
- Prettier integrated for code formatting.

## Usage

After cloning the repository, you can use the following npm scripts:


- `compile`: Compiles the TypeScript files to JavaScript, placing the compiled files in the `dist` directory.
- `postcompile`: Copies the locales from the `src` directory to the `dist` directory.
- `bg:start`: Prepares the environment and starts the bot in the background using pm2.
- `bg:restart`: Restarts the bot service.
- `bg:logs`: Fetches logs for the bot, defaulting to the last 1000 lines.
- `start`: Compiles the TypeScript files and starts the bot.
- `lint`: Formats the code using Prettier.

## Installation

To use this project:

1. Ensure you have Node.js (version 4 or higher) and npm (version 2 or higher) installed.
2. Clone the repository.
3. Run `npm install` to install all the dependencies and devDependencies listed.

## Dependencies

- `@grammyjs/i18n`: For internationalization support.
- `dotenv`: To manage environment variables.
- `grammy`: The framework used to create the bot.
- `mongodb`: To interact with MongoDB databases.

## DevDependencies

Includes various types, ESLint configurations, Prettier, and TypeScript for linting, formatting, and compiling the code.

## Configuration

Modify the `.env` file to include your bot tokens and any other environment-specific configurations. Additionally, tailor the `src/locales` as needed for internationalization.

## License

This project is licensed under the GPL-3.0-or-later. Please ensure you comply with the license terms while using or modifying the template.

## Contributions

Contributions are welcome. Please fork the repository, make your changes, and submit a pull request.

---

This README provides a basic outline of the ts-tg-bot package. You can expand each section with more detailed information about configuration, usage, and development practices as needed for your particular bot implementation.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"bg:restart": "npm run prepare && pm2 restart propertygram-bot",
"bg:logs": "pm2 logs telegram-bot --lines 1000 -f",
"start": "npm run compile && node .",
"start:dev": " node --watch . ",
"build:dev": "tsc -watch",
"lint": "npx prettier --write src",
"prepare": "husky install"
},
Expand Down
2 changes: 1 addition & 1 deletion src/config/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export async function startApp() {
debug("Starting app...");
try {
loadEnv();
validateEnv(["TELEGRAM_TOKEN", "DB_CONNECTION_STRING"]);
validateEnv(["TELEGRAM_TOKEN", "DB_CONNECTION_STRING", "ADMIN_GROUP_ID"]);
} catch (error) {
console.error("Error occurred while loading environment:", error);
process.exit(1);
Expand Down
11 changes: 7 additions & 4 deletions src/config/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ import type { I18n } from "@grammyjs/i18n/dist/source/i18n.js";
import { Bot as TelegramBot, session } from "grammy";

import { resolvePath } from "../helpers/resolve-path.js";
import { createReplyWithTextFunc } from "../services/context.js";
import { createReplyWithTextFunc } from "../services/context.service.js";
import type { CustomContext } from "../types/context.js";
import type { Chat, Database } from "../types/database.js";
import { initLocaleEngine } from "./locale-engine.js";
import { startController } from "../controllers/start.js";
import { stopController } from "../controllers/stop.js";
import type { Bot } from "../types/telegram.js";
import { buildName, getOrCreatePlayer } from "../services/user.js";
import { getOrCreateChat } from "../services/chat.js";
import { buildName, getOrCreatePlayer } from "../services/user.service.js";
import { getOrCreateChat } from "../services/chat.service.js";
import { propertiesController } from "../controllers/properties.js";
import { fileIdController } from "../controllers/fileId.js";
import { contactSalesController } from "../controllers/contactSales.js";

function extendContext(bot: Bot, database: Database) {
bot.use(async (ctx, next) => {
Expand All @@ -38,7 +39,8 @@ function extendContext(bot: Bot, database: Database) {
userId: ctx.from.id,
name: buildName(ctx.from.first_name, ctx.from.last_name)
}),
chat
chat,
property: null
};

await next();
Expand All @@ -56,6 +58,7 @@ function setupControllers(bot: Bot) {
bot.use(stopController);
bot.use(propertiesController);
bot.use(fileIdController);
bot.use(contactSalesController);
}

export async function startBot(database: Database) {
Expand Down
12 changes: 12 additions & 0 deletions src/controllers/contactSales.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Composer } from "grammy";
import type { CustomContext } from "../types/context.js";
import { notifySalesTeam } from "../services/Admin/notifySalesTeam.js";

export const contactSalesController = new Composer<CustomContext>();
contactSalesController.callbackQuery("contact-sales", async ctx => {
ctx.answerCallbackQuery("");
ctx.reply(
"Your request has been registered - an agent will contact you shortly"
);
notifySalesTeam(ctx);
});
12 changes: 8 additions & 4 deletions src/controllers/start.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { Composer } from "grammy";
import type { CustomContext } from "../types/context.js";
import { startMenu } from "../menus/startMenu.js";

export const startController = new Composer<CustomContext>();
startController.command("start", async ctx => {
await ctx.text("start", {
name: ctx.config.user.name,
chatName: ctx.config.chat?.title ?? "PM"
});
const salisolLogoUrl =
"https://lh3.googleusercontent.com/u/0/drive-viewer/AEYmBYSo6VRezOEbJpP0wzkLbT9JQ_f_HbNJw_MgzN45az99ZU5qvOe3Ad5N7qWGlHg_5iIUrRO-2sb82LOgcd-cOuBt8vNLSg=w2560-h1204";
await ctx.replyWithPhoto(salisolLogoUrl);
await ctx.reply(
`Hello ${ctx.config.user.name}, welcome to SaliSol☀️🏠 - 30 years developing properties on Spain's Costa Blanca.\nHow can we help you?`,
{ reply_markup: startMenu }
);
});
1 change: 1 addition & 0 deletions src/environment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export declare global {
interface ProcessEnv {
TELEGRAM_TOKEN: string;
DB_CONNECTION_STRING: string;
ADMIN_GROUP_ID: string;
}
}
}
20 changes: 11 additions & 9 deletions src/menus/propertyMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import { InlineKeyboard } from "grammy";

export const fullPropertyControlKeyboard = new InlineKeyboard()
.text("« Previous Property", "previous-property")
.text("Next Property » ", "next-property");
.text("Next Property » ", "next-property")
.row()
.text("Contact me about this property", "contact-sales");

export const nextPropertyControlKeyboard = new InlineKeyboard().text(
"Next Property » ",
"next-property"
);
export const nextPropertyControlKeyboard = new InlineKeyboard()
.text("Next Property » ", "next-property")
.row()
.text("Contact me about this property", "contact-sales");

export const previousPropertyControlKeyboard = new InlineKeyboard().text(
"« Previous Property",
"previous-property"
);
export const previousPropertyControlKeyboard = new InlineKeyboard()
.text("« Previous Property", "previous-property")
.row()
.text("Contact me about this property", "contact-sales");
10 changes: 10 additions & 0 deletions src/menus/startMenu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { InlineKeyboard } from "grammy";

const salisolParkWebsiteUrl = "https://salisolpark.com/";

export const startMenu = new InlineKeyboard()
.text("🏠 View Developments", "view-developments")
.row()
.text("📞 Contact sales", "contact-sales")
.row()
.url("🌐 Visit website", salisolParkWebsiteUrl);
17 changes: 17 additions & 0 deletions src/services/Admin/notifySalesTeam.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { CustomContext } from "../../types/context";

export const notifySalesTeam = (ctx: CustomContext) => {
const adminGroupId = process.env.ADMIN_GROUP_ID;
const userId = ctx.config.user.userId;
const userName = ctx.config.user.name;
const propertyOfInterest = null;
const userClickable = `[${userName}](tg://user?id=${userId})`;

const formattedNotificationMessage = `A new client is requesting information:\nName: ${userName}\nUser: @${userClickable}\n${
propertyOfInterest ? `Interested in ${propertyOfInterest}` : ""
}`;

ctx.api.sendMessage(adminGroupId, formattedNotificationMessage, {
parse_mode: "MarkdownV2"
});
};
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 2 additions & 1 deletion src/types/context.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Context, SessionFlavor } from "grammy";
import type { I18nContextFlavor, TemplateData } from "@grammyjs/i18n";
import type { Extra } from "./telegram.js";
import type { Chat, Database, User } from "./database.js";
import type { Chat, Database, Property, User } from "./database.js";

export interface Custom<C extends Context> {
text: (
Expand All @@ -13,6 +13,7 @@ export interface Custom<C extends Context> {
config: {
user: User;
chat: Chat | null;
property: Property | null;
};

db: Database;
Expand Down

0 comments on commit 512681d

Please sign in to comment.