forked from Kieran/zap.stream
Merge pull request 'feat: allow to configure a stream goal' (#90) from stream-goal into main
Reviewed-on: Kieran/stream#90 Reviewed-by: Kieran <kieran@noreply.localhost>
This commit is contained in:
commit
a278c530e6
@ -12,7 +12,6 @@ import { Profile } from "element/profile";
|
|||||||
import { ChatMessage } from "element/chat-message";
|
import { ChatMessage } from "element/chat-message";
|
||||||
import { Goal } from "element/goal";
|
import { Goal } from "element/goal";
|
||||||
import { Badge } from "element/badge";
|
import { Badge } from "element/badge";
|
||||||
import { NewGoalDialog } from "element/new-goal";
|
|
||||||
import { WriteMessage } from "element/write-message";
|
import { WriteMessage } from "element/write-message";
|
||||||
import useEmoji, { packId } from "hooks/emoji";
|
import useEmoji, { packId } from "hooks/emoji";
|
||||||
import { useLiveChatFeed } from "hooks/live-chat";
|
import { useLiveChatFeed } from "hooks/live-chat";
|
||||||
@ -117,7 +116,6 @@ export function LiveChat({
|
|||||||
<TopZappers zaps={zaps} />
|
<TopZappers zaps={zaps} />
|
||||||
</div>
|
</div>
|
||||||
{goal && <Goal ev={goal} />}
|
{goal && <Goal ev={goal} />}
|
||||||
{login?.pubkey === host && <NewGoalDialog link={link} />}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="messages">
|
<div className="messages">
|
||||||
|
@ -2,19 +2,15 @@ import "./new-goal.css";
|
|||||||
import * as Dialog from "@radix-ui/react-dialog";
|
import * as Dialog from "@radix-ui/react-dialog";
|
||||||
|
|
||||||
import AsyncButton from "./async-button";
|
import AsyncButton from "./async-button";
|
||||||
import { NostrLink } from "@snort/system";
|
|
||||||
import { Icon } from "element/icon";
|
import { Icon } from "element/icon";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { System } from "index";
|
import { System } from "index";
|
||||||
import { GOAL } from "const";
|
import { GOAL } from "const";
|
||||||
import { useLogin } from "hooks/login";
|
import { useLogin } from "hooks/login";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
import { defaultRelays } from "const";
|
||||||
|
|
||||||
interface NewGoalDialogProps {
|
export function NewGoalDialog() {
|
||||||
link: NostrLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function NewGoalDialog({ link }: NewGoalDialogProps) {
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
|
|
||||||
@ -26,12 +22,9 @@ export function NewGoalDialog({ link }: NewGoalDialogProps) {
|
|||||||
if (pub) {
|
if (pub) {
|
||||||
const evNew = await pub.generic(eb => {
|
const evNew = await pub.generic(eb => {
|
||||||
eb.kind(GOAL)
|
eb.kind(GOAL)
|
||||||
.tag(["a", `${link.kind}:${link.author}:${link.id}`])
|
|
||||||
.tag(["amount", String(Number(goalAmount) * 1000)])
|
.tag(["amount", String(Number(goalAmount) * 1000)])
|
||||||
|
.tag(["relays", ...Object.keys(defaultRelays)])
|
||||||
.content(goalName);
|
.content(goalName);
|
||||||
if (link.relays?.length) {
|
|
||||||
eb.tag(["relays", ...link.relays]);
|
|
||||||
}
|
|
||||||
return eb;
|
return eb;
|
||||||
});
|
});
|
||||||
console.debug(evNew);
|
console.debug(evNew);
|
||||||
|
@ -3,12 +3,14 @@ import { useEffect, useState, useCallback } from "react";
|
|||||||
import { NostrEvent } from "@snort/system";
|
import { NostrEvent } from "@snort/system";
|
||||||
import { unixNow } from "@snort/shared";
|
import { unixNow } from "@snort/shared";
|
||||||
import { TagsInput } from "react-tag-input-component";
|
import { TagsInput } from "react-tag-input-component";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import AsyncButton from "./async-button";
|
import AsyncButton from "./async-button";
|
||||||
import { StreamState } from "../index";
|
import { StreamState } from "../index";
|
||||||
import { findTag } from "../utils";
|
import { findTag } from "../utils";
|
||||||
import { useLogin } from "hooks/login";
|
import { useLogin } from "hooks/login";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { NewGoalDialog } from "element/new-goal";
|
||||||
|
import { useGoals } from "hooks/goals";
|
||||||
|
|
||||||
export interface StreamEditorProps {
|
export interface StreamEditorProps {
|
||||||
ev?: NostrEvent;
|
ev?: NostrEvent;
|
||||||
@ -24,6 +26,27 @@ export interface StreamEditorProps {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GoalSelectorProps {
|
||||||
|
goal?: string;
|
||||||
|
pubkey: string;
|
||||||
|
onGoalSelect: (g: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function GoalSelector({ goal, pubkey, onGoalSelect }: GoalSelectorProps) {
|
||||||
|
const goals = useGoals(pubkey, true);
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
return (
|
||||||
|
<select defaultValue={goal} onChange={ev => onGoalSelect(ev.target.value)}>
|
||||||
|
<option value="">{formatMessage({ defaultMessage: "Select a goal..." })}</option>
|
||||||
|
{goals?.map(goal => (
|
||||||
|
<option key={goal.id} value={goal.id}>
|
||||||
|
{goal.content}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
||||||
const [title, setTitle] = useState("");
|
const [title, setTitle] = useState("");
|
||||||
const [summary, setSummary] = useState("");
|
const [summary, setSummary] = useState("");
|
||||||
@ -34,6 +57,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
const [tags, setTags] = useState<string[]>([]);
|
const [tags, setTags] = useState<string[]>([]);
|
||||||
const [contentWarning, setContentWarning] = useState(false);
|
const [contentWarning, setContentWarning] = useState(false);
|
||||||
const [isValid, setIsValid] = useState(false);
|
const [isValid, setIsValid] = useState(false);
|
||||||
|
const [goal, setGoal] = useState<string | undefined>();
|
||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
@ -46,6 +70,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
setStart(findTag(ev, "starts"));
|
setStart(findTag(ev, "starts"));
|
||||||
setTags(ev?.tags.filter(a => a[0] === "t").map(a => a[1]) ?? []);
|
setTags(ev?.tags.filter(a => a[0] === "t").map(a => a[1]) ?? []);
|
||||||
setContentWarning(findTag(ev, "content-warning") !== undefined);
|
setContentWarning(findTag(ev, "content-warning") !== undefined);
|
||||||
|
setGoal(findTag(ev, "goal"));
|
||||||
}, [ev?.id]);
|
}, [ev?.id]);
|
||||||
|
|
||||||
const validate = useCallback(() => {
|
const validate = useCallback(() => {
|
||||||
@ -90,6 +115,9 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
if (contentWarning) {
|
if (contentWarning) {
|
||||||
eb.tag(["content-warning", "nsfw"]);
|
eb.tag(["content-warning", "nsfw"]);
|
||||||
}
|
}
|
||||||
|
if (goal && goal.length > 0) {
|
||||||
|
eb.tag(["goal", goal]);
|
||||||
|
}
|
||||||
return eb;
|
return eb;
|
||||||
});
|
});
|
||||||
console.debug(evNew);
|
console.debug(evNew);
|
||||||
@ -201,6 +229,19 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{login?.pubkey && (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage defaultMessage="Goal" />
|
||||||
|
</p>
|
||||||
|
<div className="paper">
|
||||||
|
<GoalSelector goal={goal} pubkey={login?.pubkey} onGoalSelect={setGoal} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NewGoalDialog />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{(options?.canSetContentWarning ?? true) && (
|
{(options?.canSetContentWarning ?? true) && (
|
||||||
<div className="flex g12 content-warning">
|
<div className="flex g12 content-warning">
|
||||||
<div>
|
<div>
|
||||||
|
@ -1,22 +1,31 @@
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { RequestBuilder, ReplaceableNoteStore, NostrLink } from "@snort/system";
|
import { RequestBuilder, FlatNoteStore, ReplaceableNoteStore } from "@snort/system";
|
||||||
import { useRequestBuilder } from "@snort/system-react";
|
import { useRequestBuilder } from "@snort/system-react";
|
||||||
import { unwrap } from "@snort/shared";
|
|
||||||
import { GOAL } from "const";
|
import { GOAL } from "const";
|
||||||
|
|
||||||
export function useZapGoal(host: string, link?: NostrLink, leaveOpen = false) {
|
export function useZapGoal(id?: string) {
|
||||||
const sub = useMemo(() => {
|
const sub = useMemo(() => {
|
||||||
if (!link) return null;
|
if (!id) return null;
|
||||||
const b = new RequestBuilder(`goals:${host.slice(0, 12)}`);
|
const b = new RequestBuilder(`goal:${id.slice(0, 12)}`);
|
||||||
b.withOptions({ leaveOpen });
|
b.withFilter().kinds([GOAL]).ids([id]);
|
||||||
b.withFilter()
|
|
||||||
.kinds([GOAL])
|
|
||||||
.authors([host])
|
|
||||||
.tag("a", [`${link.kind}:${unwrap(link.author)}:${link.id}`]);
|
|
||||||
return b;
|
return b;
|
||||||
}, [link, leaveOpen]);
|
}, [id]);
|
||||||
|
|
||||||
const { data } = useRequestBuilder(ReplaceableNoteStore, sub);
|
const { data } = useRequestBuilder(ReplaceableNoteStore, sub);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useGoals(pubkey?: string, leaveOpen = false) {
|
||||||
|
const sub = useMemo(() => {
|
||||||
|
if (!pubkey) return null;
|
||||||
|
const b = new RequestBuilder(`goals:${pubkey.slice(0, 12)}`);
|
||||||
|
b.withOptions({ leaveOpen });
|
||||||
|
b.withFilter().kinds([GOAL]).authors([pubkey]);
|
||||||
|
return b;
|
||||||
|
}, [pubkey, leaveOpen]);
|
||||||
|
|
||||||
|
const { data } = useRequestBuilder(FlatNoteStore, sub);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
@ -190,6 +190,16 @@ input[type="number"] {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
font-family: inherit;
|
||||||
|
border: unset;
|
||||||
|
background-color: unset;
|
||||||
|
color: inherit;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
"0GfNiL": {
|
"0GfNiL": {
|
||||||
"defaultMessage": "Stream Zap Goals"
|
"defaultMessage": "Stream Zap Goals"
|
||||||
},
|
},
|
||||||
|
"0VV/sK": {
|
||||||
|
"defaultMessage": "Goal"
|
||||||
|
},
|
||||||
"1EYCdR": {
|
"1EYCdR": {
|
||||||
"defaultMessage": "Tags"
|
"defaultMessage": "Tags"
|
||||||
},
|
},
|
||||||
@ -128,6 +131,9 @@
|
|||||||
"HAlOn1": {
|
"HAlOn1": {
|
||||||
"defaultMessage": "Name"
|
"defaultMessage": "Name"
|
||||||
},
|
},
|
||||||
|
"I/TubD": {
|
||||||
|
"defaultMessage": "Select a goal..."
|
||||||
|
},
|
||||||
"I1kjHI": {
|
"I1kjHI": {
|
||||||
"defaultMessage": "Supports {markdown}"
|
"defaultMessage": "Supports {markdown}"
|
||||||
},
|
},
|
||||||
|
@ -114,7 +114,7 @@ export function StreamPage({ link, evPreload }: { evPreload?: NostrEvent; link:
|
|||||||
const ev = useCurrentStreamFeed(link, true, evPreload);
|
const ev = useCurrentStreamFeed(link, true, evPreload);
|
||||||
const host = getHost(ev);
|
const host = getHost(ev);
|
||||||
const evLink = ev ? eventToLink(ev) : undefined;
|
const evLink = ev ? eventToLink(ev) : undefined;
|
||||||
const goal = useZapGoal(host, evLink, true);
|
const goal = useZapGoal(findTag(ev, "goal"));
|
||||||
|
|
||||||
const title = findTag(ev, "title");
|
const title = findTag(ev, "title");
|
||||||
const summary = findTag(ev, "summary");
|
const summary = findTag(ev, "summary");
|
||||||
|
@ -59,12 +59,14 @@ export class Nip103StreamProvider implements StreamProvider {
|
|||||||
const image = findTag(ev, "image");
|
const image = findTag(ev, "image");
|
||||||
const tags = ev?.tags.filter(a => a[0] === "t").map(a => a[1]);
|
const tags = ev?.tags.filter(a => a[0] === "t").map(a => a[1]);
|
||||||
const contentWarning = findTag(ev, "content-warning");
|
const contentWarning = findTag(ev, "content-warning");
|
||||||
|
const goal = findTag(ev, "goal");
|
||||||
await this.#getJson("PATCH", "event", {
|
await this.#getJson("PATCH", "event", {
|
||||||
title,
|
title,
|
||||||
summary,
|
summary,
|
||||||
image,
|
image,
|
||||||
tags,
|
tags,
|
||||||
content_warning: contentWarning,
|
content_warning: contentWarning,
|
||||||
|
goal,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
"/GCoTA": "Clear",
|
"/GCoTA": "Clear",
|
||||||
"04lmFi": "Save Key",
|
"04lmFi": "Save Key",
|
||||||
"0GfNiL": "Stream Zap Goals",
|
"0GfNiL": "Stream Zap Goals",
|
||||||
|
"0VV/sK": "Goal",
|
||||||
"1EYCdR": "Tags",
|
"1EYCdR": "Tags",
|
||||||
"1qsXCO": "eg. name@wallet.com",
|
"1qsXCO": "eg. name@wallet.com",
|
||||||
"2/2yg+": "Add",
|
"2/2yg+": "Add",
|
||||||
@ -42,6 +43,7 @@
|
|||||||
"H/bNs9": "Save this and keep it safe! If you lose this key, you won't be able to access your account ever again. Yep, it's that serious!",
|
"H/bNs9": "Save this and keep it safe! If you lose this key, you won't be able to access your account ever again. Yep, it's that serious!",
|
||||||
"H5+NAX": "Balance",
|
"H5+NAX": "Balance",
|
||||||
"HAlOn1": "Name",
|
"HAlOn1": "Name",
|
||||||
|
"I/TubD": "Select a goal...",
|
||||||
"I1kjHI": "Supports {markdown}",
|
"I1kjHI": "Supports {markdown}",
|
||||||
"IJDKz3": "Zap amount in {currency}",
|
"IJDKz3": "Zap amount in {currency}",
|
||||||
"INlWvJ": "OR",
|
"INlWvJ": "OR",
|
||||||
@ -126,4 +128,4 @@
|
|||||||
"x82IOl": "Mute",
|
"x82IOl": "Mute",
|
||||||
"yzKwBQ": "eg. nsec1xyz",
|
"yzKwBQ": "eg. nsec1xyz",
|
||||||
"zVDHAu": "Zap Alert"
|
"zVDHAu": "Zap Alert"
|
||||||
}
|
}
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Alerta de Zap"
|
"defaultMessage": "Alerta de Zap"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "هشدار زپ"
|
"defaultMessage": "هشدار زپ"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "ザップアラート"
|
"defaultMessage": "ザップアラート"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Tahadhari ya Zap"
|
"defaultMessage": "Tahadhari ya Zap"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,4 +381,3 @@
|
|||||||
"defaultMessage": "Zap Alert"
|
"defaultMessage": "Zap Alert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user