Skip to content
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
265 changes: 136 additions & 129 deletions src/components/setting/NotificationSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import SlackIcon from "@/assets/logo/social-logo/plain/slack.svg?react";

type TNotificationSectionProps = {
email: string;
isAdmin: boolean;
masterEnabled: boolean;
onMasterEnabledChange: (value: boolean) => void;
//channel
Expand Down Expand Up @@ -48,6 +49,7 @@ type TNotificationSectionProps = {

export default function NotificationSection({
email,
isAdmin,
masterEnabled,
onMasterEnabledChange,
browserPush,
Expand Down Expand Up @@ -158,140 +160,145 @@ export default function NotificationSection({
/>
</div>
</div>

<div className="flex items-center gap-4 py-5 tablet:flex-col tablet:items-stretch">
<div className="flex min-w-0 flex-1 items-center gap-4">
<SlackIcon className={rowIconClass} />
<div className="min-w-0">
<p className="font-body1 text-text-title">슬랙 연동하기</p>
<p className="font-body2 text-text-muted">
{slackConnected
? "연동됨 • 알림 on/off는 저장 시 반영"
: "Webhook URL로 연동"}
</p>
{isAdmin && (
<div className="flex items-center gap-4 py-5">
<div className="flex min-w-0 flex-1 items-center gap-4">
<SlackIcon className={rowIconClass} />
<div className="min-w-0">
<p className="font-body1 text-text-title">슬랙 연동하기</p>
<p className="font-body2 text-text-muted">
{slackConnected
? "연동됨 • 알림 on/off는 저장 시 반영"
: "Webhook URL로 연동"}
</p>
</div>
</div>
{slackConnected ? (
<div className="flex shrink-0 items-center gap-3">
{slackEnabled && !channelDisabled && (
<Badge variant="infoBlue">켜짐</Badge>
)}
<Toggle
checked={slackEnabled}
disabled={channelDisabled || isAnyOrgPending}
onToggle={() => onSlackEnabledChange(!slackEnabled)}
ariaLabel="슬랙 알림 켜기/끄기"
/>
<Button
variant="outline"
size="small"
type="button"
disabled={channelDisabled || isAnyOrgPending}
isLoading={isSlackPending}
onClick={onDisconnectSlack}
>
연동 해제
</Button>
</div>
) : (
<>
<Input
aria-label="슬랙 Webhook URL"
placeholder="https://hooks.slack.com/..."
value={slackWebhookUrl}
onChange={(e) => onSlackWebhookUrlChange(e.target.value)}
error={!!slackWebhookError}
helperText={slackWebhookError}
disabled={channelDisabled || isAnyOrgPending}
wrapperClassName="w-1/4 shrink-0"
containerClassName="h-10 rounded-lg"
inputClassName="px-3 font-body2"
/>
<Button
variant="outline"
size="small"
type="button"
className="shrink-0"
disabled={
channelDisabled ||
isAnyOrgPending ||
!slackWebhookUrl.trim()
}
isLoading={isSlackPending}
onClick={onConnectSlack}
>
연동
</Button>
</>
)}
</div>
{slackConnected ? (
<div className="flex shrink-0 items-center gap-3 tablet:justify-between">
{slackEnabled && !channelDisabled && (
<Badge variant="infoBlue">켜짐</Badge>
)}
<Toggle
checked={slackEnabled}
disabled={channelDisabled || isAnyOrgPending}
onToggle={() => onSlackEnabledChange(!slackEnabled)}
ariaLabel="슬랙 알림 켜기/끄기"
/>
<Button
variant="outline"
size="small"
type="button"
disabled={channelDisabled || isAnyOrgPending}
isLoading={isSlackPending}
onClick={onDisconnectSlack}
>
연동 해제
</Button>
</div>
) : (
<div className="flex shrink-0 items-center gap-3 tablet:w-full tablet:flex-col tablet:items-stretch">
<Input
aria-label="슬랙 Webhook URL"
placeholder="https://hooks.slack.com/..."
value={slackWebhookUrl}
onChange={(e) => onSlackWebhookUrlChange(e.target.value)}
error={!!slackWebhookError}
helperText={slackWebhookError}
disabled={channelDisabled || isAnyOrgPending}
wrapperClassName="w-1/4 shrink-0 tablet:w-full"
containerClassName="h-10 rounded-lg"
inputClassName="px-3 font-body2"
/>
<Button
variant="outline"
size="small"
type="button"
className="shrink-0 tablet:w-full"
disabled={
channelDisabled ||
isAnyOrgPending ||
!slackWebhookUrl.trim()
}
isLoading={isSlackPending}
onClick={onConnectSlack}
>
연동
</Button>
</div>
)}
</div>
)}

<div className="flex items-center gap-4 py-5 last:pb-0">
<div className="flex min-w-0 flex-1 items-center gap-4">
<DiscordIcon className={rowIconClass} />
<div className="min-w-0">
<p className="font-body1 text-text-title">디스코드 연동하기</p>
<p className="font-body2 text-text-muted">
{discordConnected
? "연동됨 • 알림 on/off는 저장 시 반영"
: "Webhook URL로 연동"}
</p>
{isAdmin && (
<div className="flex items-center gap-4 py-5 last:pb-0">
<div className="flex min-w-0 flex-1 items-center gap-4">
<DiscordIcon className={rowIconClass} />
<div className="min-w-0">
<p className="font-body1 text-text-title">
디스코드 연동하기
</p>
<p className="font-body2 text-text-muted">
{discordConnected
? "연동됨 • 알림 on/off는 저장 시 반영"
: "Webhook URL로 연동"}
</p>
</div>
</div>
{discordConnected ? (
<div className="flex shrink-0 items-center gap-3">
{discordEnabled && !channelDisabled && (
<Badge variant="infoBlue">켜짐</Badge>
)}
<Toggle
checked={discordEnabled}
disabled={channelDisabled || isAnyOrgPending}
onToggle={() => onDiscordEnabledChange(!discordEnabled)}
ariaLabel="디스코드 알림 켜기/끄기"
/>
<Button
variant="outline"
size="small"
type="button"
disabled={channelDisabled || isAnyOrgPending}
isLoading={isDiscordPending}
onClick={onDisconnectDiscord}
>
연동 해제
</Button>
</div>
) : (
<>
<Input
aria-label="디스코드 Webhook URL"
placeholder="https://discord.com/api/webhooks/..."
value={discordWebhookUrl}
onChange={(e) => onDiscordWebhookUrlChange(e.target.value)}
error={!!discordWebhookError}
helperText={discordWebhookError}
disabled={channelDisabled || isAnyOrgPending}
wrapperClassName="w-1/4 shrink-0"
containerClassName="h-10 rounded-lg"
inputClassName="px-3 font-body2"
/>
<Button
variant="outline"
size="small"
type="button"
className="shrink-0"
disabled={
channelDisabled ||
isAnyOrgPending ||
!discordWebhookUrl.trim()
}
isLoading={isDiscordPending}
onClick={onConnectDiscord}
>
연동
</Button>
</>
)}
</div>
{discordConnected ? (
<div className="flex shrink-0 items-center gap-3 tablet:justify-between">
{discordEnabled && !channelDisabled && (
<Badge variant="infoBlue">켜짐</Badge>
)}
<Toggle
checked={discordEnabled}
disabled={channelDisabled || isAnyOrgPending}
onToggle={() => onDiscordEnabledChange(!discordEnabled)}
ariaLabel="디스코드 알림 켜기/끄기"
/>
<Button
variant="outline"
size="small"
type="button"
disabled={channelDisabled || isAnyOrgPending}
isLoading={isDiscordPending}
onClick={onDisconnectDiscord}
>
연동 해제
</Button>
</div>
) : (
<div className="flex shrink-0 items-center gap-3 tablet:w-full tablet:flex-col tablet:items-stretch">
<Input
aria-label="디스코드 Webhook URL"
placeholder="https://discord.com/api/webhooks/..."
value={discordWebhookUrl}
onChange={(e) => onDiscordWebhookUrlChange(e.target.value)}
error={!!discordWebhookError}
helperText={discordWebhookError}
disabled={channelDisabled || isAnyOrgPending}
wrapperClassName="w-1/4 shrink-0 tablet:w-full"
containerClassName="h-10 rounded-lg"
inputClassName="px-3 font-body2"
/>
<Button
variant="outline"
size="small"
type="button"
className="shrink-0 tablet:w-full"
disabled={
channelDisabled ||
isAnyOrgPending ||
!discordWebhookUrl.trim()
}
isLoading={isDiscordPending}
onClick={onConnectDiscord}
>
연동
</Button>
</div>
)}
</div>
)}
</div>
</section>

Expand Down
9 changes: 8 additions & 1 deletion src/pages/setting/Setting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ export default function Setting() {
getMyWorkspaces,
);

const myRole = useWorkspaceStore((s) => s.myRole);
const isAdmin = myRole === "ADMIN";

const {
data: notificationSettings,
isLoading: isNotificationLoading,
Expand Down Expand Up @@ -419,7 +422,10 @@ export default function Setting() {
const shouldSaveMaster =
canSaveNotification && hasMasterChanges && selectedOrgId != null;
const shouldSaveOrg =
canSaveNotification && hasOrgToggleChanges && selectedOrgId != null;
canSaveNotification &&
hasOrgToggleChanges &&
selectedOrgId != null &&
isAdmin;

if (
shouldSaveChannel ||
Expand Down Expand Up @@ -648,6 +654,7 @@ export default function Setting() {
>
<NotificationSection
email={draftProfile.email}
isAdmin={isAdmin}
masterEnabled={draftOrgNotif.masterEnabled}
onMasterEnabledChange={(value) => {
if (!value) {
Expand Down
Loading