Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
7 changes: 7 additions & 0 deletions dist/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
},
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["https://*.coupang.com/*"],
"js": ["js/contentScript.js"],
"run_at": "document_idle"
}
],
"background": {
"service_worker": "js/backgroundPage.js"
},
Expand Down
1 change: 1 addition & 0 deletions dist/popup.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Chrome Extension (built with TypeScript + React)</title>
<script src="js/popup.js"></script>
</head>
Expand Down
2 changes: 1 addition & 1 deletion src/popup/__tests__/test_popup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { Popup } from "../component";
import { Popup } from "../getProduct";
import renderer from "react-test-renderer";

it("component renders", () => {
Expand Down
74 changes: 0 additions & 74 deletions src/popup/component.tsx

This file was deleted.

67 changes: 67 additions & 0 deletions src/popup/getProduct.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useState } from "react";
import "../css/app.css";

const Component = () => {
const [productInfo, setProductInfo] = useState<{
productId: string;
productTitle: string;
} | null>(null);

const [error, setError] = useState("");

const getProductInfo = () => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (!tabs[0]?.id) return;

Comment on lines +13 to +15
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion

Add error handling for query failure

The current implementation doesn't handle potential errors when querying tabs. Consider adding proper error handling.

- chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
-     if (!tabs[0]?.id) return;
+ chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
+     if (!tabs[0]?.id) {
+         setError("ν™œμ„±ν™”λœ 탭을 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.");
+         return;
+     }
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (!tabs[0]?.id) return;
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (!tabs[0]?.id) {
setError("ν™œμ„±ν™”λœ 탭을 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.");
return;
}

chrome.tabs.sendMessage(
tabs[0].id,
{ type: "GET_PRODUCT_INFO" },
(response) => {
if (response?.matched) {
const { productId, productTitle } = response;
setProductInfo({ productId, productTitle });
setError("");
const utterance = new SpeechSynthesisUtterance(
`μƒν’ˆλͺ…은 ${productTitle}이고, μƒν’ˆ μ•„μ΄λ””λŠ” ${productId}μž…λ‹ˆλ‹€.`,
);
utterance.lang = "ko-KR";
speechSynthesis.speak(utterance);
} else {
setProductInfo(null);
setError(
"❗ ν˜„μž¬ νŽ˜μ΄μ§€λŠ” 'μ‹ν’ˆ' μΉ΄ν…Œκ³ λ¦¬κ°€ μ•„λ‹™λ‹ˆλ‹€.",
);
}
},
);
Comment on lines +16 to +36
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion

Add error handling for message sending failures

The current implementation doesn't handle the case where message sending fails or returns undefined. Add error handling for runtime.lastError.

chrome.tabs.sendMessage(
    tabs[0].id,
    { type: "GET_PRODUCT_INFO" },
    (response) => {
+       if (chrome.runtime.lastError) {
+           setError("λ©”μ‹œμ§€ 전솑 μ‹€νŒ¨: " + chrome.runtime.lastError.message);
+           return;
+       }
+       
+       if (!response) {
+           setError("응닡이 μ—†μŠ΅λ‹ˆλ‹€. νŽ˜μ΄μ§€μ—μ„œ μ½˜ν…μΈ  μŠ€ν¬λ¦½νŠΈκ°€ μ‹€ν–‰ 쀑인지 ν™•μΈν•˜μ„Έμš”.");
+           return;
+       }
        
        if (response?.matched) {
            const { productId, productTitle } = response;
            setProductInfo({ productId, productTitle });
            setError("");
            const utterance = new SpeechSynthesisUtterance(
                `μƒν’ˆλͺ…은 ${productTitle}이고, μƒν’ˆ μ•„μ΄λ””λŠ” ${productId}μž…λ‹ˆλ‹€.`,
            );
            utterance.lang = "ko-KR";
            speechSynthesis.speak(utterance);
        } else {
            setProductInfo(null);
            setError(
                "❗ ν˜„μž¬ νŽ˜μ΄μ§€λŠ” 'μ‹ν’ˆ' μΉ΄ν…Œκ³ λ¦¬κ°€ μ•„λ‹™λ‹ˆλ‹€.",
            );
        }
    },
);
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
chrome.tabs.sendMessage(
tabs[0].id,
{ type: "GET_PRODUCT_INFO" },
(response) => {
if (response?.matched) {
const { productId, productTitle } = response;
setProductInfo({ productId, productTitle });
setError("");
const utterance = new SpeechSynthesisUtterance(
`μƒν’ˆλͺ…은 ${productTitle}이고, μƒν’ˆ μ•„μ΄λ””λŠ” ${productId}μž…λ‹ˆλ‹€.`,
);
utterance.lang = "ko-KR";
speechSynthesis.speak(utterance);
} else {
setProductInfo(null);
setError(
"❗ ν˜„μž¬ νŽ˜μ΄μ§€λŠ” 'μ‹ν’ˆ' μΉ΄ν…Œκ³ λ¦¬κ°€ μ•„λ‹™λ‹ˆλ‹€.",
);
}
},
);
chrome.tabs.sendMessage(
tabs[0].id,
{ type: "GET_PRODUCT_INFO" },
(response) => {
if (chrome.runtime.lastError) {
setError("λ©”μ‹œμ§€ 전솑 μ‹€νŒ¨: " + chrome.runtime.lastError.message);
return;
}
if (!response) {
setError("응닡이 μ—†μŠ΅λ‹ˆλ‹€. νŽ˜μ΄μ§€μ—μ„œ μ½˜ν…μΈ  μŠ€ν¬λ¦½νŠΈκ°€ μ‹€ν–‰ 쀑인지 ν™•μΈν•˜μ„Έμš”.");
return;
}
if (response?.matched) {
const { productId, productTitle } = response;
setProductInfo({ productId, productTitle });
setError("");
const utterance = new SpeechSynthesisUtterance(
`μƒν’ˆλͺ…은 ${productTitle}이고, μƒν’ˆ μ•„μ΄λ””λŠ” ${productId}μž…λ‹ˆλ‹€.`,
);
utterance.lang = "ko-KR";
speechSynthesis.speak(utterance);
} else {
setProductInfo(null);
setError(
"❗ ν˜„μž¬ νŽ˜μ΄μ§€λŠ” 'μ‹ν’ˆ' μΉ΄ν…Œκ³ λ¦¬κ°€ μ•„λ‹™λ‹ˆλ‹€.",
);
}
},
);

});
};
return (
<div className="w-72 p-4 bg-white rounded-lg shadow-lg">
<h1 className="text-xl font-semibold mb-3 text-gray-800">
VOIM μƒν’ˆ 리더기
</h1>

<button
onClick={getProductInfo}
className="w-full py-2 bg-blue-600 hover:bg-blue-700 text-white rounded text-sm mb-2"
>
μƒν’ˆ 정보 μ½μ–΄μ€˜!
</button>
{productInfo && (
<div className="mt-4 text-sm text-gray-700">
<p>
<strong>μƒν’ˆλͺ…:</strong> {productInfo.productTitle}
</p>
<p>
<strong>μƒν’ˆ ID:</strong> {productInfo.productId}
</p>
</div>
)}

{error && <p className="mt-4 text-red-500 text-sm">{error}</p>}
</div>
);
};

export default Component;
11 changes: 7 additions & 4 deletions src/popup/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import * as React from "react";
import { createRoot } from "react-dom/client";
import browser from "webextension-polyfill";
import { Popup } from "./component";
import GetProduct from "./getProduct";
import "../css/app.css";

// // // //

browser.tabs
.query({ active: true, currentWindow: true })
.then(() => {
Expand All @@ -21,7 +19,12 @@ browser.tabs
const container = document.getElementById("popup");
if (container) {
const root = createRoot(container);
root.render(<Popup />);
root.render(
<div className="p-4 w-80">
<h1 className="text-lg font-bold mb-4">VOIM</h1>
<GetProduct />
</div>,
);
} else {
console.error("popupμ΄λΌλŠ” idλ₯Ό κ°€μ§„ μš”μ†Œκ°€ μ‘΄μž¬ν•˜μ§€ μ•Šμ•„μš”!");
}
Expand Down
2 changes: 1 addition & 1 deletion src/popup/stories/Popup.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { Popup } from "../component";
import { Popup } from "../getProduct";
import { Meta } from "@storybook/react";

// // // //
Expand Down