Skip to content

Commit

Permalink
click on zap contact to add
Browse files Browse the repository at this point in the history
  • Loading branch information
futurepaul committed Feb 6, 2024
1 parent 38856f7 commit dda2f7a
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 159 deletions.
31 changes: 4 additions & 27 deletions src/components/ContactViewer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SubmitHandler } from "@modular-forms/solid";
import { TagItem } from "@mutinywallet/mutiny-wasm";
import { useNavigate } from "@solidjs/router";
import { createSignal, Match, Show, Switch } from "solid-js";
import { createSignal, JSX, Match, Show, Switch } from "solid-js";

import {
Button,
Expand All @@ -25,8 +25,8 @@ export type ContactFormValues = {
};

export function ContactViewer(props: {
children: JSX.Element;
contact: TagItem;
gradient: string;
saveContact: (id: string, contact: ContactFormValues) => void;
deleteContact: (id: string) => Promise<void>;
}) {
Expand Down Expand Up @@ -80,25 +80,7 @@ export function ContactViewer(props: {

return (
<>
<button
onClick={() => setIsOpen(true)}
class="flex w-16 flex-shrink-0 flex-col items-center gap-2 overflow-x-hidden"
>
<div
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"
style={{ background: props.gradient }}
>
<Switch>
<Match when={props.contact.image_url}>
<img src={props.contact.image_url} />
</Match>
<Match when={true}>{props.contact.name[0]}</Match>
</Switch>
</div>
<SmallHeader class="h-4 w-16 overflow-hidden overflow-ellipsis text-center">
{props.contact.name}
</SmallHeader>
</button>
<button onClick={() => setIsOpen(true)}>{props.children}</button>
<SimpleDialog
open={isOpen()}
setOpen={setIsOpen}
Expand Down Expand Up @@ -129,12 +111,7 @@ export function ContactViewer(props: {
<Match when={!isEditing()}>
<div class="mx-auto flex w-full max-w-[400px] flex-1 flex-col items-center justify-around gap-4">
<div class="flex w-full flex-col items-center">
<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"
style={{
background: props.gradient
}}
>
<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">
<Switch>
<Match when={props.contact.image_url}>
<img
Expand Down
25 changes: 21 additions & 4 deletions src/components/GenericItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export function GenericItem(props: {
showFiat?: boolean;
genericAvatar?: boolean;
forceSecondary?: boolean;
link?: string;
primaryOnClick?: () => void;
secondaryOnClick?: () => void;
}) {
return (
<div
Expand All @@ -36,6 +39,7 @@ export function GenericItem(props: {
contact
image_url={props.primaryAvatarUrl}
generic={props.genericAvatar}
onClick={props.primaryOnClick}
/>
</div>
<div class="flex flex-col items-start gap-1 px-2">
Expand Down Expand Up @@ -73,7 +77,7 @@ export function GenericItem(props: {
</Show>
{/* OPTIONAL MESSAGE */}
<Show when={props.message}>
<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">
<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">
{props.message}
</div>
</Show>
Expand All @@ -89,9 +93,21 @@ export function GenericItem(props: {
<PrivateEye />
{/* <img src={privateEye} width={12} height={12} /> */}
</Show>
<span class="text-xs text-m-grey-400">
{props.date}
</span>
<Show when={props.link}>
<a
href={props.link}
class="text-xs text-m-grey-400"
target="_blank"
rel="noopener noreferrer"
>
{props.date}
</a>
</Show>
<Show when={!props.link}>
<span class="text-xs text-m-grey-400">
{props.date}
</span>
</Show>
</div>
</Show>
</div>
Expand All @@ -102,6 +118,7 @@ export function GenericItem(props: {
name={props.secondaryName}
contact
image_url={props.secondaryAvatarUrl}
onClick={props.secondaryOnClick}
/>
</div>
</Show>
Expand Down
47 changes: 47 additions & 0 deletions src/components/NostrActivity.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { MutinyWallet } from "@mutinywallet/mutiny-wasm";
import { useNavigate } from "@solidjs/router";
import {
createEffect,
createResource,
Expand Down Expand Up @@ -70,6 +72,44 @@ export function NostrActivity() {
}
});

const navigate = useNavigate();

// TODO: can this be part of mutiny wallet?
async function newContactFromHexpub(hexpub: string) {
try {
const profile = data.latest?.profiles[hexpub];
if (!profile) return;
const parsed = JSON.parse(profile.content);
const name = parsed.display_name || parsed.name || profile.pubkey;
const image_url = parsed.image || parsed.picture || undefined;
const npub = await MutinyWallet.hexpub_to_npub(hexpub);
const ln_address = parsed.lud16 || undefined;
const lnurl = parsed.lud06 || undefined;

const contactId = await state.mutiny_wallet?.create_new_contact(
name,
npub,
ln_address,
lnurl,
image_url
);

if (!contactId) {
throw new Error("no contact id returned");
}

const tagItem = await state.mutiny_wallet?.get_tag_item(contactId);

if (!tagItem) {
throw new Error("no contact returned");
}

navigate(`/chat/${contactId}`);
} catch (e) {
console.error(e);
}
}

return (
<div class="flex w-full flex-col divide-y divide-m-grey-800 overflow-x-clip">
<For each={data.latest?.zaps}>
Expand All @@ -86,10 +126,16 @@ export function NostrActivity() {
? i18n.t("activity.private")
: nameFromHexpub(zap.from_hexpub)
}
primaryOnClick={() => {
newContactFromHexpub(zap.from_hexpub);
}}
secondaryAvatarUrl={
imageFromHexpub(zap.to_hexpub) || ""
}
secondaryName={nameFromHexpub(zap.to_hexpub)}
secondaryOnClick={() => {
newContactFromHexpub(zap.to_hexpub);
}}
verb={"zapped"}
amount={zap.amount_sats}
message={zap.content ? zap.content : undefined}
Expand All @@ -100,6 +146,7 @@ export function NostrActivity() {
zap.kind === "private"
}
forceSecondary
link={`https://njump.me/e/${zap.event_id}`}
/>
<Show when={false}>
<div
Expand Down
11 changes: 7 additions & 4 deletions src/routes/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
BackPop,
Button,
ContactButton,
ContactViewer,
HackActivityType,
IActivityItem,
LoadingShimmer,
Expand Down Expand Up @@ -460,10 +461,12 @@ export function Chat() {
{/* <BackLink href="/" /> */}
<BackPop default="/search" />
<Show when={contact()}>
<ContactButton
contact={contact()!}
onClick={() => {}}
/>
<ContactViewer>

Check failure on line 464 in src/routes/Chat.tsx

View workflow job for this annotation

GitHub Actions / code_quality

Type '{ children: Element; }' is not assignable to type 'IntrinsicAttributes & { children: Element; contact: TagItem; saveContact: (id: string, contact: ContactFormValues) => void; deleteContact: (id: string) => Promise<...>; }'.

Check failure on line 464 in src/routes/Chat.tsx

View workflow job for this annotation

GitHub Actions / Build APK

Type '{ children: Element; }' is not assignable to type 'IntrinsicAttributes & { children: Element; contact: TagItem; saveContact: (id: string, contact: ContactFormValues) => void; deleteContact: (id: string) => Promise<...>; }'.

Check failure on line 464 in src/routes/Chat.tsx

View workflow job for this annotation

GitHub Actions / Build iOS

Type '{ children: Element; }' is not assignable to type 'IntrinsicAttributes & { children: Element; contact: TagItem; saveContact: (id: string, contact: ContactFormValues) => void; deleteContact: (id: string) => Promise<...>; }'.
<ContactButton
contact={contact()!}
onClick={() => {}}
/>
</ContactViewer>
</Show>
</div>
<div class="h-[8rem]" />
Expand Down
122 changes: 1 addition & 121 deletions src/routes/Scratchpad.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,127 +7,7 @@ import { Clock } from "~/assets/svg/Clock";
import { Globe } from "~/assets/svg/Globe";
import { PrivateEye } from "~/assets/svg/Private";
import { LabelCircle } from "~/components";

function GenericItem(props: {
primaryAvatarUrl: string;
secondaryAvatarUrl?: string;
primaryName: string;
secondaryName?: string;
verb: string;
amount: bigint;
date: string;
due?: string;
message?: string;
accent?: "green";
public?: boolean;
showFiat?: boolean;
}) {
return (
<div
class="grid py-3"
classList={{
"grid-cols-[auto_1fr_auto]": true
}}
>
<div class="self-center">
<LabelCircle
label={false}
name={props.primaryName}
contact
image_url={props.primaryAvatarUrl}
/>
</div>
<div class="flex flex-col items-start gap-1 px-2">
{/* TITLE TEXT */}
<h2 class="text-sm">
<strong>{props.primaryName}</strong>
<span class="font-light">{` ${props.verb} `}</span>
<Show when={props.secondaryName}>
<strong>{props.secondaryName}</strong>
</Show>
</h2>
<div class="flex flex-wrap gap-1">
{/* AMOUNT */}
<div
class="flex items-center gap-1 rounded-full px-2 py-1 text-xs font-semibold text-white"
classList={{
"bg-m-grey-800": !props.accent,
"bg-m-green/40 ": props.accent === "green"
}}
>
<img src={bolt} width={8} height={8} />
{`${props.amount.toLocaleString()} sats`}
</div>
{/* FIAT AMOUNT */}
<Show when={props.showFiat}>
<div class="flex items-center gap-1 rounded-full py-1 text-xs font-semibold text-m-grey-400">
{`~$42.00 USD`}
</div>
</Show>
{/* OPTIONAL MESSAGE */}
<Show when={props.message}>
<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">
{props.message}
</div>
</Show>
</div>
{/* DATE WITH SECOND AVATAR */}
<Show when={props.secondaryAvatarUrl}>
<div class="flex items-center gap-1 text-m-grey-400">
<Show when={props.public}>
{/* <img src={globe} width={12} height={12} /> */}
<Globe />
</Show>
<Show when={!props.public}>
<PrivateEye />
{/* <img src={privateEye} width={12} height={12} /> */}
</Show>
<span class="text-xs text-m-grey-400">
{props.date}
</span>
</div>
</Show>
</div>
<Show when={props.secondaryAvatarUrl}>
<div class="self-center">
<LabelCircle
label={false}
name={props.secondaryName}
contact
image_url={props.secondaryAvatarUrl}
/>
</div>
</Show>
<Show when={!props.secondaryAvatarUrl}>
<div class="self-center">
{/* DATE */}
<div class="flex items-center gap-1 text-m-grey-400">
<Show when={props.public}>
{/* <img src={globe} width={12} height={12} /> */}
<Globe />
</Show>
<Show when={!props.public}>
<PrivateEye />
{/* <img src={privateEye} width={12} height={12} /> */}
</Show>
<span class="text-xs text-m-grey-400">
{props.date}
</span>
</div>
{/* DUE */}
<Show when={props.due}>
<div class="flex items-center gap-1 text-m-grey-400">
<Clock />
<span class="text-xs text-m-grey-400">
{props.due}
</span>
</div>
</Show>
</div>
</Show>
</div>
);
}
import { GenericItem } from "~/components/GenericItem";

const PAUL =
"https://cdn.satellite.earth/75fc2f4692566ddf090748e8d53cb1863ec93fa784ccedd533dcdd9ecbad159d.gif";
Expand Down
6 changes: 3 additions & 3 deletions src/utils/fetchZaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ export const fetchZaps: ResourceFetcher<
// Parse the primal response
for (const object of data) {
if (object.kind === 10000113) {
console.log("got a 10000113 object", object);
// console.log("got a 10000113 object", object);
try {
const content = JSON.parse(object.content);
if (content?.until) {
Expand All @@ -265,12 +265,12 @@ export const fetchZaps: ResourceFetcher<
}

if (object.kind === 0) {
console.log("got a 0 object", object);
// console.log("got a 0 object", object);
profiles[object.pubkey] = object as NostrProfile;
}

if (object.kind === 9735) {
console.log("got a 9735 object", object);
// console.log("got a 9735 object", object);
try {
const event = await simpleZapFromEvent(
object,
Expand Down

0 comments on commit dda2f7a

Please sign in to comment.