Skip to content
This repository was archived by the owner on Apr 21, 2025. It is now read-only.

Commit dda2f7a

Browse files
committed
click on zap contact to add
1 parent 38856f7 commit dda2f7a

File tree

6 files changed

+83
-159
lines changed

6 files changed

+83
-159
lines changed

src/components/ContactViewer.tsx

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SubmitHandler } from "@modular-forms/solid";
22
import { TagItem } from "@mutinywallet/mutiny-wasm";
33
import { useNavigate } from "@solidjs/router";
4-
import { createSignal, Match, Show, Switch } from "solid-js";
4+
import { createSignal, JSX, Match, Show, Switch } from "solid-js";
55

66
import {
77
Button,
@@ -25,8 +25,8 @@ export type ContactFormValues = {
2525
};
2626

2727
export function ContactViewer(props: {
28+
children: JSX.Element;
2829
contact: TagItem;
29-
gradient: string;
3030
saveContact: (id: string, contact: ContactFormValues) => void;
3131
deleteContact: (id: string) => Promise<void>;
3232
}) {
@@ -80,25 +80,7 @@ export function ContactViewer(props: {
8080

8181
return (
8282
<>
83-
<button
84-
onClick={() => setIsOpen(true)}
85-
class="flex w-16 flex-shrink-0 flex-col items-center gap-2 overflow-x-hidden"
86-
>
87-
<div
88-
class="flex h-16 w-16 flex-none items-center justify-center overflow-clip rounded-full border-b border-t border-b-white/10 border-t-white/50 text-4xl uppercase"
89-
style={{ background: props.gradient }}
90-
>
91-
<Switch>
92-
<Match when={props.contact.image_url}>
93-
<img src={props.contact.image_url} />
94-
</Match>
95-
<Match when={true}>{props.contact.name[0]}</Match>
96-
</Switch>
97-
</div>
98-
<SmallHeader class="h-4 w-16 overflow-hidden overflow-ellipsis text-center">
99-
{props.contact.name}
100-
</SmallHeader>
101-
</button>
83+
<button onClick={() => setIsOpen(true)}>{props.children}</button>
10284
<SimpleDialog
10385
open={isOpen()}
10486
setOpen={setIsOpen}
@@ -129,12 +111,7 @@ export function ContactViewer(props: {
129111
<Match when={!isEditing()}>
130112
<div class="mx-auto flex w-full max-w-[400px] flex-1 flex-col items-center justify-around gap-4">
131113
<div class="flex w-full flex-col items-center">
132-
<div
133-
class="flex h-32 w-32 flex-none items-center justify-center overflow-clip rounded-full border-b border-t border-b-white/10 border-t-white/50 text-8xl uppercase"
134-
style={{
135-
background: props.gradient
136-
}}
137-
>
114+
<div class="flex h-32 w-32 flex-none items-center justify-center overflow-clip rounded-full border-b border-t border-b-white/10 border-t-white/50 text-8xl uppercase">
138115
<Switch>
139116
<Match when={props.contact.image_url}>
140117
<img

src/components/GenericItem.tsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ export function GenericItem(props: {
2121
showFiat?: boolean;
2222
genericAvatar?: boolean;
2323
forceSecondary?: boolean;
24+
link?: string;
25+
primaryOnClick?: () => void;
26+
secondaryOnClick?: () => void;
2427
}) {
2528
return (
2629
<div
@@ -36,6 +39,7 @@ export function GenericItem(props: {
3639
contact
3740
image_url={props.primaryAvatarUrl}
3841
generic={props.genericAvatar}
42+
onClick={props.primaryOnClick}
3943
/>
4044
</div>
4145
<div class="flex flex-col items-start gap-1 px-2">
@@ -73,7 +77,7 @@ export function GenericItem(props: {
7377
</Show>
7478
{/* OPTIONAL MESSAGE */}
7579
<Show when={props.message}>
76-
<div class="font-regular line-clamp-1 min-w-0 flex-1 break-all rounded-full bg-m-grey-800 px-2 text-xs leading-6">
80+
<div class="font-regular line-clamp-1 min-w-0 flex-shrink break-all rounded-full bg-m-grey-800 px-2 text-xs leading-6">
7781
{props.message}
7882
</div>
7983
</Show>
@@ -89,9 +93,21 @@ export function GenericItem(props: {
8993
<PrivateEye />
9094
{/* <img src={privateEye} width={12} height={12} /> */}
9195
</Show>
92-
<span class="text-xs text-m-grey-400">
93-
{props.date}
94-
</span>
96+
<Show when={props.link}>
97+
<a
98+
href={props.link}
99+
class="text-xs text-m-grey-400"
100+
target="_blank"
101+
rel="noopener noreferrer"
102+
>
103+
{props.date}
104+
</a>
105+
</Show>
106+
<Show when={!props.link}>
107+
<span class="text-xs text-m-grey-400">
108+
{props.date}
109+
</span>
110+
</Show>
95111
</div>
96112
</Show>
97113
</div>
@@ -102,6 +118,7 @@ export function GenericItem(props: {
102118
name={props.secondaryName}
103119
contact
104120
image_url={props.secondaryAvatarUrl}
121+
onClick={props.secondaryOnClick}
105122
/>
106123
</div>
107124
</Show>

src/components/NostrActivity.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { MutinyWallet } from "@mutinywallet/mutiny-wasm";
2+
import { useNavigate } from "@solidjs/router";
13
import {
24
createEffect,
35
createResource,
@@ -70,6 +72,44 @@ export function NostrActivity() {
7072
}
7173
});
7274

75+
const navigate = useNavigate();
76+
77+
// TODO: can this be part of mutiny wallet?
78+
async function newContactFromHexpub(hexpub: string) {
79+
try {
80+
const profile = data.latest?.profiles[hexpub];
81+
if (!profile) return;
82+
const parsed = JSON.parse(profile.content);
83+
const name = parsed.display_name || parsed.name || profile.pubkey;
84+
const image_url = parsed.image || parsed.picture || undefined;
85+
const npub = await MutinyWallet.hexpub_to_npub(hexpub);
86+
const ln_address = parsed.lud16 || undefined;
87+
const lnurl = parsed.lud06 || undefined;
88+
89+
const contactId = await state.mutiny_wallet?.create_new_contact(
90+
name,
91+
npub,
92+
ln_address,
93+
lnurl,
94+
image_url
95+
);
96+
97+
if (!contactId) {
98+
throw new Error("no contact id returned");
99+
}
100+
101+
const tagItem = await state.mutiny_wallet?.get_tag_item(contactId);
102+
103+
if (!tagItem) {
104+
throw new Error("no contact returned");
105+
}
106+
107+
navigate(`/chat/${contactId}`);
108+
} catch (e) {
109+
console.error(e);
110+
}
111+
}
112+
73113
return (
74114
<div class="flex w-full flex-col divide-y divide-m-grey-800 overflow-x-clip">
75115
<For each={data.latest?.zaps}>
@@ -86,10 +126,16 @@ export function NostrActivity() {
86126
? i18n.t("activity.private")
87127
: nameFromHexpub(zap.from_hexpub)
88128
}
129+
primaryOnClick={() => {
130+
newContactFromHexpub(zap.from_hexpub);
131+
}}
89132
secondaryAvatarUrl={
90133
imageFromHexpub(zap.to_hexpub) || ""
91134
}
92135
secondaryName={nameFromHexpub(zap.to_hexpub)}
136+
secondaryOnClick={() => {
137+
newContactFromHexpub(zap.to_hexpub);
138+
}}
93139
verb={"zapped"}
94140
amount={zap.amount_sats}
95141
message={zap.content ? zap.content : undefined}
@@ -100,6 +146,7 @@ export function NostrActivity() {
100146
zap.kind === "private"
101147
}
102148
forceSecondary
149+
link={`https://njump.me/e/${zap.event_id}`}
103150
/>
104151
<Show when={false}>
105152
<div

src/routes/Chat.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
BackPop,
2727
Button,
2828
ContactButton,
29+
ContactViewer,
2930
HackActivityType,
3031
IActivityItem,
3132
LoadingShimmer,
@@ -460,10 +461,12 @@ export function Chat() {
460461
{/* <BackLink href="/" /> */}
461462
<BackPop default="/search" />
462463
<Show when={contact()}>
463-
<ContactButton
464-
contact={contact()!}
465-
onClick={() => {}}
466-
/>
464+
<ContactViewer>
465+
<ContactButton
466+
contact={contact()!}
467+
onClick={() => {}}
468+
/>
469+
</ContactViewer>
467470
</Show>
468471
</div>
469472
<div class="h-[8rem]" />

src/routes/Scratchpad.tsx

Lines changed: 1 addition & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -7,127 +7,7 @@ import { Clock } from "~/assets/svg/Clock";
77
import { Globe } from "~/assets/svg/Globe";
88
import { PrivateEye } from "~/assets/svg/Private";
99
import { LabelCircle } from "~/components";
10-
11-
function GenericItem(props: {
12-
primaryAvatarUrl: string;
13-
secondaryAvatarUrl?: string;
14-
primaryName: string;
15-
secondaryName?: string;
16-
verb: string;
17-
amount: bigint;
18-
date: string;
19-
due?: string;
20-
message?: string;
21-
accent?: "green";
22-
public?: boolean;
23-
showFiat?: boolean;
24-
}) {
25-
return (
26-
<div
27-
class="grid py-3"
28-
classList={{
29-
"grid-cols-[auto_1fr_auto]": true
30-
}}
31-
>
32-
<div class="self-center">
33-
<LabelCircle
34-
label={false}
35-
name={props.primaryName}
36-
contact
37-
image_url={props.primaryAvatarUrl}
38-
/>
39-
</div>
40-
<div class="flex flex-col items-start gap-1 px-2">
41-
{/* TITLE TEXT */}
42-
<h2 class="text-sm">
43-
<strong>{props.primaryName}</strong>
44-
<span class="font-light">{` ${props.verb} `}</span>
45-
<Show when={props.secondaryName}>
46-
<strong>{props.secondaryName}</strong>
47-
</Show>
48-
</h2>
49-
<div class="flex flex-wrap gap-1">
50-
{/* AMOUNT */}
51-
<div
52-
class="flex items-center gap-1 rounded-full px-2 py-1 text-xs font-semibold text-white"
53-
classList={{
54-
"bg-m-grey-800": !props.accent,
55-
"bg-m-green/40 ": props.accent === "green"
56-
}}
57-
>
58-
<img src={bolt} width={8} height={8} />
59-
{`${props.amount.toLocaleString()} sats`}
60-
</div>
61-
{/* FIAT AMOUNT */}
62-
<Show when={props.showFiat}>
63-
<div class="flex items-center gap-1 rounded-full py-1 text-xs font-semibold text-m-grey-400">
64-
{`~$42.00 USD`}
65-
</div>
66-
</Show>
67-
{/* OPTIONAL MESSAGE */}
68-
<Show when={props.message}>
69-
<div class="font-regular line-clamp-1 min-w-0 flex-1 break-all rounded-full bg-m-grey-800 px-2 text-xs leading-6">
70-
{props.message}
71-
</div>
72-
</Show>
73-
</div>
74-
{/* DATE WITH SECOND AVATAR */}
75-
<Show when={props.secondaryAvatarUrl}>
76-
<div class="flex items-center gap-1 text-m-grey-400">
77-
<Show when={props.public}>
78-
{/* <img src={globe} width={12} height={12} /> */}
79-
<Globe />
80-
</Show>
81-
<Show when={!props.public}>
82-
<PrivateEye />
83-
{/* <img src={privateEye} width={12} height={12} /> */}
84-
</Show>
85-
<span class="text-xs text-m-grey-400">
86-
{props.date}
87-
</span>
88-
</div>
89-
</Show>
90-
</div>
91-
<Show when={props.secondaryAvatarUrl}>
92-
<div class="self-center">
93-
<LabelCircle
94-
label={false}
95-
name={props.secondaryName}
96-
contact
97-
image_url={props.secondaryAvatarUrl}
98-
/>
99-
</div>
100-
</Show>
101-
<Show when={!props.secondaryAvatarUrl}>
102-
<div class="self-center">
103-
{/* DATE */}
104-
<div class="flex items-center gap-1 text-m-grey-400">
105-
<Show when={props.public}>
106-
{/* <img src={globe} width={12} height={12} /> */}
107-
<Globe />
108-
</Show>
109-
<Show when={!props.public}>
110-
<PrivateEye />
111-
{/* <img src={privateEye} width={12} height={12} /> */}
112-
</Show>
113-
<span class="text-xs text-m-grey-400">
114-
{props.date}
115-
</span>
116-
</div>
117-
{/* DUE */}
118-
<Show when={props.due}>
119-
<div class="flex items-center gap-1 text-m-grey-400">
120-
<Clock />
121-
<span class="text-xs text-m-grey-400">
122-
{props.due}
123-
</span>
124-
</div>
125-
</Show>
126-
</div>
127-
</Show>
128-
</div>
129-
);
130-
}
10+
import { GenericItem } from "~/components/GenericItem";
13111

13212
const PAUL =
13313
"https://cdn.satellite.earth/75fc2f4692566ddf090748e8d53cb1863ec93fa784ccedd533dcdd9ecbad159d.gif";

src/utils/fetchZaps.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ export const fetchZaps: ResourceFetcher<
253253
// Parse the primal response
254254
for (const object of data) {
255255
if (object.kind === 10000113) {
256-
console.log("got a 10000113 object", object);
256+
// console.log("got a 10000113 object", object);
257257
try {
258258
const content = JSON.parse(object.content);
259259
if (content?.until) {
@@ -265,12 +265,12 @@ export const fetchZaps: ResourceFetcher<
265265
}
266266

267267
if (object.kind === 0) {
268-
console.log("got a 0 object", object);
268+
// console.log("got a 0 object", object);
269269
profiles[object.pubkey] = object as NostrProfile;
270270
}
271271

272272
if (object.kind === 9735) {
273-
console.log("got a 9735 object", object);
273+
// console.log("got a 9735 object", object);
274274
try {
275275
const event = await simpleZapFromEvent(
276276
object,

0 commit comments

Comments
 (0)