Skip to content

Commit 018f0ae

Browse files
authored
[Feat] 문의용 채널톡 추가 (#144)
* feat: 채널톡 서비스 추가 * refactor: 채널톡 버튼 기본 설정 값 변경 * refactor: 말투 예시보기 버튼 width 삭제 * refactor: 홈 navbar 수정 * refactor: 공유 텍스트 스토어 링크 추가
1 parent 0a2f0dd commit 018f0ae

File tree

10 files changed

+334
-62
lines changed

10 files changed

+334
-62
lines changed

src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { Outlet } from "react-router-dom";
22

3+
import { useChannelTalk } from "@/hooks/common/useChannelTalk";
34
import useHotjar from "@/hooks/common/useHotjar";
45

56
const App = () => {
67
useHotjar();
8+
useChannelTalk();
79

810
return (
911
<main>

src/assets/svg/ic-logo.svg

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/assets/svg/ic-share.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
/* eslint-disable prefer-rest-params */
2+
/* eslint-disable @typescript-eslint/no-explicit-any */
3+
declare global {
4+
interface Window {
5+
ChannelIO?: IChannelIO;
6+
7+
ChannelIOInitialized?: boolean;
8+
}
9+
}
10+
11+
interface IChannelIO {
12+
c?: (...args: any) => void;
13+
14+
q?: [methodName: string, ...args: any[]][];
15+
16+
(...args: any): void;
17+
}
18+
19+
interface BootOption {
20+
appearance?: string;
21+
22+
customLauncherSelector?: string;
23+
24+
hideChannelButtonOnBoot?: boolean;
25+
26+
hidePopup?: boolean;
27+
28+
language?: string;
29+
30+
memberHash?: string;
31+
32+
memberId?: string;
33+
34+
pluginKey: string;
35+
36+
profile?: Profile;
37+
38+
trackDefaultEvent?: boolean;
39+
40+
trackUtmSource?: boolean;
41+
42+
unsubscribe?: boolean;
43+
44+
unsubscribeEmail?: boolean;
45+
46+
unsubscribeTexting?: boolean;
47+
48+
zIndex?: number;
49+
}
50+
51+
interface Callback {
52+
(error: Error | null, user: CallbackUser | null): void;
53+
}
54+
55+
interface CallbackUser {
56+
alert: number;
57+
58+
avatarUrl: string;
59+
60+
id: string;
61+
62+
language: string;
63+
64+
memberId: string;
65+
66+
name?: string;
67+
68+
profile?: Profile | null;
69+
70+
tags?: string[] | null;
71+
72+
unsubscribeEmail: boolean;
73+
74+
unsubscribeTexting: boolean;
75+
}
76+
77+
interface UpdateUserInfo {
78+
language?: string;
79+
80+
profile?: Profile | null;
81+
82+
profileOnce?: Profile;
83+
84+
tags?: string[] | null;
85+
86+
unsubscribeEmail?: boolean;
87+
88+
unsubscribeTexting?: boolean;
89+
}
90+
91+
interface Profile {
92+
[key: string]: string | number | boolean | null | undefined;
93+
}
94+
95+
interface FollowUpProfile {
96+
name?: string | null;
97+
98+
mobileNumber?: string | null;
99+
100+
email?: string | null;
101+
}
102+
103+
interface EventProperty {
104+
[key: string]: string | number | boolean | null | undefined;
105+
}
106+
107+
type Appearance = "light" | "dark" | "system" | null;
108+
109+
class ChannelService {
110+
loadScript() {
111+
(function () {
112+
const w = window;
113+
114+
if (w.ChannelIO || w.ChannelIOInitialized) {
115+
return;
116+
}
117+
118+
if (w.ChannelIO) {
119+
return w.console.error("ChannelIO script included twice.");
120+
}
121+
122+
const ch: IChannelIO = function () {
123+
ch.c?.(arguments);
124+
};
125+
126+
ch.q = [];
127+
128+
ch.c = function (args) {
129+
ch.q?.push(args);
130+
};
131+
132+
w.ChannelIO = ch;
133+
134+
function l() {
135+
if (w.ChannelIOInitialized) {
136+
return;
137+
}
138+
139+
w.ChannelIOInitialized = true;
140+
141+
const s = document.createElement("script");
142+
143+
s.type = "text/javascript";
144+
145+
s.async = true;
146+
147+
s.src = "https://cdn.channel.io/plugin/ch-plugin-web.js";
148+
149+
const x = document.getElementsByTagName("script")[0];
150+
151+
if (x.parentNode) {
152+
x.parentNode.insertBefore(s, x);
153+
}
154+
}
155+
156+
if (document.readyState === "complete") {
157+
l();
158+
} else {
159+
w.addEventListener("DOMContentLoaded", l);
160+
161+
w.addEventListener("load", l);
162+
}
163+
})();
164+
}
165+
166+
boot(option: BootOption, callback?: Callback) {
167+
window.ChannelIO?.("boot", option, callback);
168+
}
169+
170+
shutdown() {
171+
window.ChannelIO?.("shutdown");
172+
}
173+
174+
showMessenger() {
175+
window.ChannelIO?.("showMessenger");
176+
}
177+
178+
hideMessenger() {
179+
window.ChannelIO?.("hideMessenger");
180+
}
181+
182+
openChat(chatId?: string | number, message?: string) {
183+
window.ChannelIO?.("openChat", chatId, message);
184+
}
185+
186+
track(eventName: string, eventProperty?: EventProperty) {
187+
window.ChannelIO?.("track", eventName, eventProperty);
188+
}
189+
190+
onShowMessenger(callback: () => void) {
191+
window.ChannelIO?.("onShowMessenger", callback);
192+
}
193+
194+
onHideMessenger(callback: () => void) {
195+
window.ChannelIO?.("onHideMessenger", callback);
196+
}
197+
198+
onBadgeChanged(callback: (unread: number, alert: number) => void) {
199+
window.ChannelIO?.("onBadgeChanged", callback);
200+
}
201+
202+
onChatCreated(callback: () => void) {
203+
window.ChannelIO?.("onChatCreated", callback);
204+
}
205+
206+
onFollowUpChanged(callback: (profile: FollowUpProfile) => void) {
207+
window.ChannelIO?.("onFollowUpChanged", callback);
208+
}
209+
210+
onUrlClicked(callback: (url: string) => void) {
211+
window.ChannelIO?.("onUrlClicked", callback);
212+
}
213+
214+
clearCallbacks() {
215+
window.ChannelIO?.("clearCallbacks");
216+
}
217+
218+
updateUser(userInfo: UpdateUserInfo, callback?: Callback) {
219+
window.ChannelIO?.("updateUser", userInfo, callback);
220+
}
221+
222+
addTags(tags: string[], callback?: Callback) {
223+
window.ChannelIO?.("addTags", tags, callback);
224+
}
225+
226+
removeTags(tags: string[], callback?: Callback) {
227+
window.ChannelIO?.("removeTags", tags, callback);
228+
}
229+
230+
setPage(page: string) {
231+
window.ChannelIO?.("setPage", page);
232+
}
233+
234+
resetPage() {
235+
window.ChannelIO?.("resetPage");
236+
}
237+
238+
showChannelButton() {
239+
window.ChannelIO?.("showChannelButton");
240+
}
241+
242+
hideChannelButton() {
243+
window.ChannelIO?.("hideChannelButton");
244+
}
245+
246+
setAppearance(appearance: Appearance) {
247+
window.ChannelIO?.("setAppearance", appearance);
248+
}
249+
}
250+
251+
export default new ChannelService();

src/components/Navbar/Navbar.stories.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ export const HomeNavbar: Story = {
2727
name: "HomeNavbar",
2828
render: () => (
2929
<Navbar>
30-
<Navbar.LeftButton>
31-
<Icon name="logo" />
32-
</Navbar.LeftButton>
3330
<Navbar.RightButton>
3431
<Text variant="bodySm" color="secondary">
3532
앱 공유하기

src/components/ui/Icon/Icon.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import CloseIcon from "@/assets/svg/ic-close.svg?react";
44
import EmptyCircleIcon from "@/assets/svg/ic-empty-circle.svg?react";
55
import GalleryIcon from "@/assets/svg/ic-gallery.svg?react";
66
import LeftArrowIcon from "@/assets/svg/ic-left-arrow.svg?react";
7-
import LogoIcon from "@/assets/svg/ic-logo.svg?react";
87
import PasteIcon from "@/assets/svg/ic-paste.svg?react";
98
import PlusIcon from "@/assets/svg/ic-plus.svg?react";
9+
import ShareIcon from "@/assets/svg/ic-share.svg?react";
1010

1111
export type IconNameType =
1212
| "camera"
@@ -17,7 +17,7 @@ export type IconNameType =
1717
| "plus"
1818
| "checkCircle"
1919
| "emptyCircle"
20-
| "logo";
20+
| "share";
2121

2222
export interface IconProps {
2323
name: IconNameType;
@@ -32,7 +32,7 @@ export const ICONS = {
3232
plus: PlusIcon,
3333
checkCircle: CheckCircleIcon,
3434
emptyCircle: EmptyCircleIcon,
35-
logo: LogoIcon,
35+
share: ShareIcon,
3636
};
3737

3838
// 추후 사이즈, 컬러등 추가 가능

src/hooks/common/useChannelTalk.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { useEffect } from "react";
2+
3+
import ChannelService from "@/components/ChannelTalk/channelTalk";
4+
5+
export const useChannelTalk = () => {
6+
const openChannelTalk = () => {
7+
ChannelService.showMessenger();
8+
};
9+
10+
useEffect(() => {
11+
ChannelService.loadScript();
12+
13+
ChannelService.boot({
14+
pluginKey: import.meta.env.VITE_CHANNEL_TALK_KEY || "",
15+
hideChannelButtonOnBoot: true,
16+
});
17+
}, []);
18+
19+
return { openChannelTalk };
20+
};

0 commit comments

Comments
 (0)