8000 Develop by Stivenjs · Pull Request #7 · Fasttify/fasttify-core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Develop #7

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

Merged
merged 9 commits into from
May 2, 2025
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
15 changes: 13 additions & 2 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ AUTH_CORS=http://localhost:5173,http://localhost:9000,https://docs.medusajs.com
REDIS_URL=redis://localhost:6379
JWT_SECRET=supersecret
COOKIE_SECRET=supersecret
DATABASE_URL=
DATABASE_URL=postgres://postgres:"your_posgrest_password"@localhost:5432/medusa-core-fasttify
DB_NAME=medusa-core-fasttify
POSTGRES_URL=
POSTGRES_URL=
ALGOLIA_APP_ID=
ALGOLIA_API_KEY=
ALGOLIA_PRODUCT_INDEX_NAME=products
RESEND_API_KEY=
RESEND_FROM_EMAIL=onboarding@resend.dev
S3_FILE_URL=
S3_FILE_BUCKET=
S3_FILE_REGION=us-east-2
S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY=
S3_ENDPOINT=https://s3.us-east-2.amazonaws.com
8 changes: 8 additions & 0 deletions medusa-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,13 @@ module.exports = defineConfig({
],
},
},
{
resolve: "./src/modules/algolia",
options: {
appId: process.env.ALGOLIA_APP_ID!,
apiKey: process.env.ALGOLIA_API_KEY!,
productIndexName: process.env.ALGOLIA_PRODUCT_INDEX_NAME!,
},
},
],
});
15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,30 @@
"prepare": "husky",
"lint": "next lint"
},
"lint-staged": {
"lint-staged": {
"*.{js,jsx,ts,tsx,json,css,scss,md}": [
"prettier --write"
]
},
"dependencies": {
"@medusajs/admin-sdk": "2.6.1",
"@medusajs/cli": "2.6.1",
"@medusajs/framework": "2.6.1",
"@medusajs/medusa": "2.6.1",
"@medusajs/admin-sdk": "2.7.1",
"@medusajs/cli": "2.7.1",
"@medusajs/framework": "2.7.1",
"@medusajs/medusa": "2.7.1",
"@mikro-orm/core": "6.4.3",
"@mikro-orm/knex": "6.4.3",
"@mikro-orm/migrations": "6.4.3",
"@mikro-orm/postgresql": "6.4.3",
"@react-email/components": "0.0.36",
"algoliasearch": "^5.23.3",
"awilix": "^8.0.1",
"husky": "^9.1.7",
"pg": "^8.13.0",
"prettier": "^3.5.3",
"resend": "^4.2.0"
},
"devDependencies": {
"@medusajs/test-utils": "2.6.1",
"@medusajs/test-utils": "2.7.1",
"@mikro-orm/cli": "6.4.3",
"@swc/core": "1.5.7",
"@swc/jest": "^0.2.36",
Expand All @@ -65,5 +66,5 @@
"engines": {
"node": ">=20"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
"packageManager": "yarn@4.1.1"
}
9 changes: 9 additions & 0 deletions src/admin/lib/sdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Medusa from "@medusajs/js-sdk";

export const sdk = new Medusa({
baseUrl: import.meta.env.VITE_BACKEND_URL || "/",
debug: import.meta.env.DEV,
auth: {
type: "session",
},
});
51 changes: 51 additions & 0 deletions src/admin/routes/settings/algolia/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Container, Heading, Button, toast, Text } from "@medusajs/ui";
import { useMutation } from "@tanstack/react-query";
import { sdk } from "../../../lib/sdk";
import { defineRouteConfig } from "@medusajs/admin-sdk";

const AlgoliaPage = () => {
const { mutate, isPending } = useMutation({
mutationFn: () =>
sdk.client.fetch("/admin/algolia/sync", {
method: "POST",
}),
onSuccess: () => {
toast.success("Sincroniización exitosa con Algolia");
},
onError: (err) => {
console.error(err);
toast.error("Error al sincronizar con Algolia");
},
});

const handleSync = () => {
mutate();
};

return (
<Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4">
<Heading level="h2">Sincronización con Algolia</Heading>
</div>
<div className="px-6">
<Text className="mb-4 mt-8">
Algolia es una plataforma de búsqueda ultrarrápida que permite
encontrar productos y contenido en tu tienda en tiempo real. Presiona
el botón para sincronizar tus datos con Algolia y mejorar la
experiencia de búsqueda.
</Text>
</div>
<div className="px-6 py-8">
<Button variant="primary" isLoading={isPending}>
Sincronizar datos con Algolia
</Button>
</div>
</Container>
);
};

export const config = defineRouteConfig({
label: "Algolia",
});

export default AlgoliaPage;
13 changes: 13 additions & 0 deletions src/api/admin/algolia/sync/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
import { Modules } from "@medusajs/framework/utils";

export async function POST(req: MedusaRequest, res: MedusaResponse) {
const eventModuleService = req.scope.resolve(Modules.EVENT_BUS);
await eventModuleService.emit({
name: "algolia.sync",
data: {},
});
res.send({
message: "Syncing data to Algolia",
});
}
15 changes: 15 additions & 0 deletions src/api/middlewares.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {
defineMiddlewares,
validateAndTransformBody,
} from "@medusajs/framework/http";
import { SearchSchema } from "./store/products/search/route";

export default defineMiddlewares({
routes: [
{
matcher: "/store/products/search",
method: ["POST"],
middlewares: [validateAndTransformBody(SearchSchema)],
},
],
});
24 changes: 24 additions & 0 deletions src/api/store/products/search/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
import { ALGOLIA_MODULE } from "../../../../modules/algolia";
import AlgoliaModuleService from "../../../../modules/algolia/service";
import { z } from "zod";

export const SearchSchema = z.object({
query: z.string(),
});

type SearchRequest = z.infer<typeof SearchSchema>;

export async function POST(
req: MedusaRequest<SearchRequest>,
res: MedusaResponse
) {
const algoliaModuleService: AlgoliaModuleService =
req.scope.resolve(ALGOLIA_MODULE);

const { query } = req.validatedBody;

const results = await algoliaModuleService.search(query as string);

res.json(results);
}
8 changes: 8 additions & 0 deletions src/modules/algolia/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from "@medusajs/framework/utils";
import AlgoliaModuleService from "./service";

export const ALGOLIA_MODULE = "algolia";

export default Module(ALGOLIA_MODULE, {
service: AlgoliaModuleService,
});
79 changes: 79 additions & 0 deletions src/modules/algolia/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { algoliasearch, SearchClient } from "algoliasearch";

type AlgoliaOptions = {
apiKey: string;
appId: string;
productIndexName: string;
};

export type AlgoliaIndexType = "product";

export default class AlgoliaModuleService {
private client: SearchClient;
private options: AlgoliaOptions;

constructor({}, options: AlgoliaOptions) {
this.client = algoliasearch(options.appId, options.apiKey);
this.options = options;
}

async getIndexName(type: AlgoliaIndexType) {
switch (type) {
case "product":
return this.options.productIndexName;
default:
throw new Error(`Invalid index type: ${type}`);
}
}

async indexData(
data: Record<string, unknown>[],
type: AlgoliaIndexType = "product"
) {
const indexName = await this.getIndexName(type);
this.client.saveObjects({
indexName,
objects: data.map((item) => ({
...item,
// set the object ID to allow updating later
objectID: item.id,
})),
});
}

async retrieveFromIndex(
objectIDs: string[],
type: AlgoliaIndexType = "product"
) {
const indexName = await this.getIndexName(type);
return await this.client.getObjects<Record<string, unknown>>({
requests: objectIDs.map((objectID) => ({
indexName,
objectID,
})),
});
}

async deleteFromIndex(
objectIDs: string[],
type: AlgoliaIndexType = "product"
) {
const indexName = await this.getIndexName(type);
await this.client.deleteObjects({
indexName,
objectIDs,
});
}

async search(query: string, type: AlgoliaIndexType = "product") {
const indexName = await this.getIndexName(type);
return await this.client.search({
requests: [
{
indexName,
query,
},
],
});
}
}
Loading
0