import { parseSpaceUri } from '@pdsjs/spaces/uri';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { ArrowRight, Boxes, Plus } from 'lucide-react';
import { useState } from 'react';
import { AppTile } from '#/components/atoms/app-tile.jsx';
import { Badge } from '#/components/atoms/badge.jsx';
import { Button } from '#/components/atoms/button.jsx';
import { Card } from '#/components/atoms/card.jsx';
import { Link } from '#/components/atoms/link.jsx';
import { Notice } from '#/components/atoms/notice.jsx';
import { Skeleton } from '#/components/atoms/skeleton.jsx';
import { ActorAvatar } from '#/components/molecules/actor-avatar.jsx';
import { AtUri } from '#/components/molecules/at-uri.jsx';
import { EmptyState } from '#/components/molecules/empty-state.jsx';
import { Identity } from '#/components/molecules/identity.jsx';
import { TextField } from '#/components/molecules/text-field.jsx';
import { spaceParts } from '#/lib/format.js';
import { href, useNavigate } from '#/lib/navigation.jsx';
import { useSession } from '#/lib/session.jsx';
import { createSpace, listSpaces } from '#/lib/spaces.js';
/** One row in the list: what the space is, and who governs it. */
function SpaceRow({ uri, isOwner, did }) {
const { spaceDid, spaceType, skey } = spaceParts(uri);
return (
{/* The space type is an NSID, and the domain it reverses to is the app
the space belongs to. Its icon says at a glance which app a space is
for, which the type alone takes a moment to read. */}
{spaceType}
{isOwner && you host this}
{skey}
{spaceDid === did ? (
'Under your own authority'
) : (
<>
Under
>
)}
);
}
/**
* The way into a space this list does not name.
*
* `listSpaces` reports the spaces this account has written to, which is what a
* PDS tracks. A space somebody has admitted this account to but which it has
* never written in appears nowhere, and its URI is the only way to reach it.
*/
function OpenByUri() {
const navigate = useNavigate();
const [uri, setUri] = useState('');
const [error, setError] = useState(null);
function open(event) {
event.preventDefault();
const trimmed = uri.trim();
try {
parseSpaceUri(trimmed);
} catch (failure) {
setError(failure.message);
return;
}
navigate(href('/space', { uri: trimmed }));
}
return (
);
}
/** The form for a space anchored on this account. */
function NewSpace({ onCreated }) {
const { session } = useSession();
const [open, setOpen] = useState(false);
const [type, setType] = useState('');
const [skey, setSkey] = useState('');
const create = useMutation({
mutationFn: () => createSpace(session, { type, skey: skey || undefined }),
onSuccess: () => {
setOpen(false);
setType('');
setSkey('');
onCreated();
},
});
if (!open) {
return (
);
}
return (
setType(event.target.value)}
/>
setSkey(event.target.value)}
/>
{create.error && {create.error.message}}
);
}
if (error) {
return (
{error.name === 'MethodNotImplemented'
? 'This PDS does not serve permissioned spaces.'
: error.message}
);
}
const spaces = data.spaces || [];
return (
The spaces your repo holds data in. A PDS tracks the spaces its own user
has written to, so a space you have been admitted to but never written
in is not listed here.
{spaces.length === 0 ? (
}
title="No spaces"
description="This account has written nothing into a permissioned space. Open one above by its URI."
/>
) : (
spaces.map((space) => (
))
)}
{writable && (
client.invalidateQueries({ queryKey: ['spaces'] })}
/>
)}