Skip to content

Commit

Permalink
Merge pull request #13 from QuantGeekDev/feature/salisol-resort-menu
Browse files Browse the repository at this point in the history
Feature/dynamic-development-menu
  • Loading branch information
QuantGeekDev authored Jan 6, 2024
2 parents 1fc4737 + bca00ec commit f0379f3
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 63 deletions.
23 changes: 23 additions & 0 deletions sampleData/developmentsSampleData.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[
{
"name": "SaliSol Resort",
"dropboxUrl": "https://www.dropbox.com/sh/t49hfiy9nlc61vh/AACAPSVNxb7w8IM8QAUYyLNVa?dl=0A",
"googleMapsUrl": "https://maps.app.goo.gl/o22J9WNxTdUcdbHR6",
"presentationVideoFileId": "12345",
"phoneNumber": "0034607862954"
},
{
"name": "SaliSol Golf",
"dropboxUrl": "https://www.dropbox.com/sh/1jl3z0t28ia86xf/AABqTv8S39H7wpmfdpJS8aQWa?dl=0",
"googleMapsUrl": "https://maps.app.goo.gl/EvzDpeqqWr3ubYxk7",
"presentationVideoFileId": "12345",
"phoneNumber": "0034607862954"
},
{
"name": "SaliSol Hills",
"dropboxUrl": "https://www.dropbox.com/sh/t6330gcog0lz7dh/AADqYOkfEnvIQ0RF6Lr0eRBja?dl=0",
"googleMapsUrl": "https://maps.app.goo.gl/FRF1Yo6D5cSDGbBGA",
"presentationVideoFileId": "12345",
"phoneNumber": "0034605632401"
}
]
File renamed without changes.
14 changes: 8 additions & 6 deletions src/config/database.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { MongoClient } from "mongodb";
import type {
Chat,
Database,
PropertyFromDb,
User
import type { DevelopmentFromDb } from "../types/database.js";
import {
type Chat,
type Database,
type PropertyFromDb,
type User
} from "../types/database.js";

export async function connectToDb() {
Expand All @@ -13,6 +14,7 @@ export async function connectToDb() {
const user = mongoDb.collection<User>("user");
const chat = mongoDb.collection<Chat>("chat");
const property = mongoDb.collection<PropertyFromDb>("properties");
const database: Database = { user, chat, property };
const development = mongoDb.collection<DevelopmentFromDb>("developments");
const database: Database = { user, chat, property, development };
return database;
}
48 changes: 30 additions & 18 deletions src/controllers/developments.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,47 @@
import { Composer } from "grammy";
import type { CustomContext } from "../types/context.js";
import { developmentsMenu } from "../menus/developmentsMenu.js";
import { ourDevelopmentsMenu } from "../menus/ourDevelopmentsMenu.js";
import { developerDetailMenuCreator } from "../menus/developmentDetailMenu.js";

export const developmentsController = new Composer<CustomContext>();
developmentsController.callbackQuery("view-developments", async ctx => {
ctx.answerCallbackQuery();
await ctx.reply("Please select the development", {
reply_markup: developmentsMenu
reply_markup: ourDevelopmentsMenu
});
});

developmentsController.callbackQuery(
"view-development:salisol-resort",
/^view-development:\s*(.+)$/,
async ctx => {
ctx.answerCallbackQuery();
await ctx.reply("SaliSol Resort Selected");
}
);
const selectedDevelopment = ctx.match[1];
let developmentName: string;
switch (selectedDevelopment) {
case "salisol-resort":
developmentName = "SaliSol Resort";
break;
case "salisol-hills":
developmentName = "SaliSol Hills";
break;
case "salisol-golf":
developmentName = "SaliSol Golf";
break;
default:
throw new Error("Development not found");
}

developmentsController.callbackQuery(
"view-development:salisol-hills",
async ctx => {
ctx.answerCallbackQuery();
await ctx.reply("SaliSol Hills Selected");
}
);

developmentsController.callbackQuery(
"view-development:salisol-golf",
async ctx => {
ctx.answerCallbackQuery();
await ctx.reply("SaliSol Golf Selected");
const development = await ctx.db.development.findOne({
name: developmentName
});
if (!development) {
return;
}
const developmentKeyboard = developerDetailMenuCreator(development);
await ctx.reply(`*${developmentName}*`, {
reply_markup: developmentKeyboard,
parse_mode: "MarkdownV2"
});
}
);
45 changes: 26 additions & 19 deletions src/controllers/properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,36 @@ import { Composer } from "grammy";
import type { CustomContext } from "../types/context.js";
import type { PropertyFromDb } from "../types/database.js";
import { displayProperty } from "../services/Property/property.service.js";
import isDevelopmentType from "../helpers/isDevelopmentType.js";

export const propertiesController = new Composer<CustomContext>();

let currentPropertyIndex = 0;

propertiesController.command("properties", async ctx => {
const properties = (await ctx.db.property
.find({})
.toArray()) as PropertyFromDb[];
await displayProperty(ctx, properties, currentPropertyIndex);
propertiesController.callbackQuery(/^view-properties \s*(.+)$/, async ctx => {
const chosenDevelopment = ctx.match[1];
ctx.answerCallbackQuery();
if (isDevelopmentType(chosenDevelopment)) {
const properties = (await ctx.db.property
.find({ development: chosenDevelopment })
.toArray()) as PropertyFromDb[];
await displayProperty(ctx, properties, currentPropertyIndex);

propertiesController.callbackQuery("next-property", async ctx => {
ctx.answerCallbackQuery("");
if (currentPropertyIndex + 1 < properties.length) {
currentPropertyIndex++;
await displayProperty(ctx, properties, currentPropertyIndex);
}
});
propertiesController.callbackQuery("next-property", async ctx => {
ctx.answerCallbackQuery("");
if (currentPropertyIndex + 1 < properties.length) {
currentPropertyIndex++;
await displayProperty(ctx, properties, currentPropertyIndex);
}
});

propertiesController.callbackQuery("previous-property", async ctx => {
ctx.answerCallbackQuery("");
if (currentPropertyIndex + 1 > 0) {
currentPropertyIndex--;
await displayProperty(ctx, properties, currentPropertyIndex);
}
});
propertiesController.callbackQuery("previous-property", async ctx => {
ctx.answerCallbackQuery("");
if (currentPropertyIndex + 1 > 0) {
currentPropertyIndex--;
await displayProperty(ctx, properties, currentPropertyIndex);
}
});
}
return;
});
11 changes: 11 additions & 0 deletions src/controllers/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,14 @@ startController.command("start", async ctx => {
{ reply_markup: startMenu }
);
});

startController.callbackQuery("start", async ctx => {
ctx.answerCallbackQuery();
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 }
);
});
11 changes: 11 additions & 0 deletions src/helpers/isDevelopmentType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { type DevelopmentType } from "../types/database";

const isDevelopmentType = (
development: string
): development is DevelopmentType => {
return ["SaliSol Hills", "SaliSol Resort", "SaliSol Golf"].includes(
development
);
};

export default isDevelopmentType;
20 changes: 20 additions & 0 deletions src/menus/developmentDetailMenu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { InlineKeyboard } from "grammy";
import type { DevelopmentFromDb } from "../types/database";

export const developerDetailMenuCreator = (
development: DevelopmentFromDb
): InlineKeyboard => {
const { name, googleMapsUrl, dropboxUrl } = development;
const developerDetailMenu = new InlineKeyboard()
.text("View Properties", `view-properties ${name}`)
.row()
.text("Request a showing", `request-showing ${name}`)
.row()
.url("📌 View on Google Maps", googleMapsUrl)
.row()
.url("🖼️ View Dropbox", dropboxUrl)
.row()
.text("🔙 Back", "view-developments");

return developerDetailMenu;
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { InlineKeyboard } from "grammy";

export const developmentsMenu = new InlineKeyboard()
export const ourDevelopmentsMenu = new InlineKeyboard()
.text(
"🏠 SaliSol Resort - Guardamar, Spain",
"view-development:salisol-resort"
)
.row()
.text("🏔️ SaliSol Hills - Benidorm, Spain", "view-development:salisol-hills")
.row()
.text("⛳ SaliSol Golf - Benidorm, Spain", "view-development:salisol-golf");
.text("⛳ SaliSol Golf - Benidorm, Spain", "view-development:salisol-golf")
.row()
.text("🔙 Back", "start");
22 changes: 10 additions & 12 deletions src/menus/propertyMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ export const fullPropertyControlKeyboard = (
.text("« Previous Property", "previous-property")
.text("Next Property » ", "next-property")
.row()
.text(
"📞 Contact me about this property",
`contact_property_${propertyId}`
);
.text("📞 Contact me about this property", `contact_property_${propertyId}`)
.row()
.text("🔙 Back", "view-developments");

return keyboard;
};

Expand All @@ -20,10 +20,9 @@ export const nextPropertyControlKeyboard = (
const keyboard = new InlineKeyboard()
.text("Next Property » ", "next-property")
.row()
.text(
"📞 Contact me about this property",
`contact_property_${propertyId}`
);
.text("📞 Contact me about this property", `contact_property_${propertyId}`)
.row()
.text("🔙 Back", "view-developments");
return keyboard;
};

Expand All @@ -33,9 +32,8 @@ export const previousPropertyControlKeyboard = (
const keyboard = new InlineKeyboard()
.text("« Previous Property", "previous-property")
.row()
.text(
"📞 Contact me about this property",
`contact_property_${propertyId}`
);
.text("📞 Contact me about this property", `contact_property_${propertyId}`)
.row()
.text("🔙 Back", "view-developments");
return keyboard;
};
Empty file added src/menus/salisolResortMenu.ts
Empty file.
2 changes: 1 addition & 1 deletion src/services/Notifications/notifySalesTeam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const notifySalesTeam = async (

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

Expand Down
8 changes: 4 additions & 4 deletions src/services/Property/property.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ export const generatePropertyDescription = (
): string => {
const {
name,
collection,
development,
availability,
price,
plotMetersSquared,
builtMetersSquared
} = property;

// Property description uses Telegram's Markdown V2
const propertyDescription = `*🏠 ${collection}: ${name}*\n\nPlot Size: ${plotMetersSquared}m2 \nBuilt Meters: ${builtMetersSquared}m2\nPrice: ${price
const propertyDescription = `*🏠 ${development}: ${name}*\n\nPlot Size: ${plotMetersSquared}m2 \nBuilt Meters: ${builtMetersSquared}m2\nPrice: ${price
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",")}${
availability ? "" : "Reserved"
Expand Down Expand Up @@ -54,7 +54,7 @@ export const displayProperty = async (
const currentPropertyId = currentProperty._id.toString();

let controlKeyboard;
if (currentPropertyIndex == 0) {
if (currentPropertyIndex == 0 && totalProperties > 1) {
controlKeyboard = nextPropertyControlKeyboard(currentPropertyId);
} else if (currentPropertyIndex + 1 < totalProperties) {
controlKeyboard = fullPropertyControlKeyboard(currentPropertyId);
Expand All @@ -72,6 +72,6 @@ export const displayProperty = async (
await ctx.replyWithVideo(videoFileId);
await ctx.replyWithMediaGroup(propertyPhotoAlbum);
await ctx.reply(`Property ${currentPropertyIndex + 1}/${totalProperties}`, {
reply_markup: controlKeyboard
reply_markup: controlKeyboard ?? undefined
});
};
17 changes: 16 additions & 1 deletion src/types/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,22 @@ export interface Property {
websiteUrl: string;
}

export interface DevelopmentFromDb {
_id: ObjectId;
name: string;
dropboxUrl: string;
googleMapsUrl: string;
presentationVideoFileId?: string;
phoneNumber: string;
}

export type DevelopmentType =
| "SaliSol Hills"
| "SaliSol Resort"
| "SaliSol Golf";
export interface PropertyFromDb {
_id: ObjectId;
collection: "SaliSol Hills" | "SaliSol Resort" | "SaliSol Golf";
development: DevelopmentType;
name: string;
price: number;
availability: boolean;
Expand All @@ -36,6 +49,7 @@ export interface PropertyFromDb {
telegramContactUrl: string;
websiteUrl: string;
}

export interface Chat {
chatId: number;
title: string;
Expand All @@ -45,4 +59,5 @@ export interface Database {
user: Collection<User>;
chat: Collection<Chat>;
property: Collection<PropertyFromDb>;
development: Collection<DevelopmentFromDb>;
}

0 comments on commit f0379f3

Please sign in to comment.