frontend client for gemstone. decentralised workplace app
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: register a shard

serenity 23d463bf 83da8218

+136 -9
+84 -6
src/components/Settings/RegisterShardModalContent.tsx
··· 1 1 import { Text } from "@/components/primitives/Text"; 2 2 import { useFacet } from "@/lib/facet"; 3 + import { registerNewShard } from "@/lib/utils/gmstn"; 4 + import { useOAuthAgentGuaranteed } from "@/providers/OAuthProvider"; 3 5 import { useCurrentPalette } from "@/providers/ThemeProvider"; 4 - import { TextInput, View } from "react-native"; 6 + import type { Dispatch, SetStateAction} from "react"; 7 + import { useState } from "react"; 8 + import { Pressable, TextInput, View } from "react-native"; 5 9 6 - export const RegisterShardModalContent = () => { 10 + export const RegisterShardModalContent = ({ 11 + setShowRegisterModal, 12 + }: { 13 + setShowRegisterModal: Dispatch<SetStateAction<boolean>>; 14 + }) => { 7 15 const { semantic } = useCurrentPalette(); 8 - const { atoms } = useFacet(); 16 + const { atoms, typography } = useFacet(); 17 + const [inputText, setInputText] = useState(""); 18 + const [registerError, setRegisterError] = useState<string | undefined>( 19 + undefined, 20 + ); 21 + const agent = useOAuthAgentGuaranteed(); 22 + const handleSubmit = async () => { 23 + const registerResult = await registerNewShard({ 24 + shardDomain: inputText, 25 + agent, 26 + }); 27 + if (!registerResult.ok) { 28 + console.error( 29 + "Something went wrong when registering the shard.", 30 + registerResult.error, 31 + ); 32 + setRegisterError(registerResult.error); 33 + return; 34 + } 35 + setShowRegisterModal(false); 36 + }; 9 37 10 38 return ( 11 39 <View ··· 13 41 backgroundColor: semantic.surface, 14 42 borderRadius: atoms.radii.lg, 15 43 display: "flex", 16 - gap: 4, 44 + gap: 12, 45 + padding: 16, 17 46 }} 18 47 > 19 - <TextInput placeholder="Hihihihiihihih" /> 20 - <Text>Hello</Text> 48 + <View style={{ gap: 4 }}> 49 + <Text>Shard domain:</Text> 50 + <TextInput 51 + style={[ 52 + { 53 + flex: 1, 54 + borderWidth: 1, 55 + borderColor: semantic.borderVariant, 56 + borderRadius: 8, 57 + paddingHorizontal: 10, 58 + paddingVertical: 10, 59 + color: semantic.text, 60 + outline: "0", 61 + fontFamily: typography.families.primary, 62 + width: 256, 63 + }, 64 + typography.weights.byName.extralight, 65 + typography.sizes.sm, 66 + ]} 67 + value={inputText} 68 + onChangeText={setInputText} 69 + placeholder="shard.gmstn.systems" 70 + placeholderTextColor={semantic.textPlaceholder} 71 + /> 72 + </View> 73 + <Pressable 74 + style={{ 75 + backgroundColor: inputText.trim() 76 + ? semantic.primary 77 + : registerError 78 + ? semantic.error 79 + : semantic.border, 80 + borderRadius: atoms.radii.lg, 81 + alignItems: "center", 82 + paddingVertical: 10, 83 + }} 84 + onPress={() => { 85 + handleSubmit().catch((e: unknown) => { 86 + console.error(e); 87 + }); 88 + }} 89 + > 90 + <Text 91 + style={[ 92 + typography.weights.byName.normal, 93 + { color: semantic.textInverse }, 94 + ]} 95 + > 96 + Register 97 + </Text> 98 + </Pressable> 21 99 </View> 22 100 ); 23 101 };
+8 -3
src/components/Settings/ShardSettings.tsx
··· 127 127 cursor: "auto", 128 128 alignItems: "center", 129 129 justifyContent: "center", 130 - backgroundColor: fade(semantic.backgroundDarker, 60), 130 + backgroundColor: fade( 131 + semantic.backgroundDarker, 132 + 60, 133 + ), 131 134 }} 132 135 onPress={() => { 133 136 setShowRegisterModal(false); ··· 143 146 e.stopPropagation(); 144 147 }} 145 148 > 146 - <RegisterShardModalContent /> 149 + <RegisterShardModalContent 150 + setShowRegisterModal={setShowRegisterModal} 151 + /> 147 152 </Pressable> 148 153 </Pressable> 149 154 </Modal> ··· 159 164 }); 160 165 161 166 if (!shards.ok) { 162 - console.error("getMembershipRecordsFromPds error.", shards.error); 167 + console.error("shardQueryFn error.", shards.error); 163 168 throw new Error( 164 169 `Something went wrong while getting the user's membership records.}`, 165 170 );
+44
src/lib/utils/gmstn.ts
··· 1 1 import type { Did } from "@/lib/types/atproto"; 2 + import type { SystemsGmstnDevelopmentShard } from "@/lib/types/lexicon/systems.gmstn.development.shard"; 2 3 import { getEndpointFromDid } from "@/lib/utils/atproto"; 4 + import { isDomain } from "@/lib/utils/domains"; 5 + import type { Result } from "@/lib/utils/result"; 6 + import type { Agent } from "@atproto/api"; 3 7 4 8 export const getLatticeEndpointFromDid = async (did: Did) => { 5 9 return await getEndpointFromDid(did, "GemstoneLattice"); ··· 16 20 endpoint.searchParams.append("token", sessionToken); 17 21 return new WebSocket(endpoint); 18 22 }; 23 + 24 + export const registerNewShard = async ({ 25 + shardDomain, 26 + agent, 27 + }: { 28 + shardDomain: string; 29 + agent: Agent; 30 + }): Promise<Result<undefined, string>> => { 31 + if (!isDomain(shardDomain)) 32 + return { ok: false, error: "Input was not a valid domain." }; 33 + 34 + const now = new Date().toISOString(); 35 + 36 + const record: Omit<SystemsGmstnDevelopmentShard, "$type"> = { 37 + // @ts-expect-error we want to explicitly use the ISO string variant 38 + createdAt: now, 39 + // TODO: actually figure out how to support the description 40 + description: "A Gemstone Systems Shard.", 41 + }; 42 + console.log(record); 43 + 44 + const { success } = await agent.call( 45 + "com.atproto.repo.createRecord", 46 + {}, 47 + { 48 + repo: agent.did, 49 + collection: "systems.gmstn.development.shard", 50 + rkey: shardDomain, 51 + record, 52 + }, 53 + ); 54 + 55 + if (!success) 56 + return { 57 + ok: false, 58 + error: "Attempted to create shard record failed. Check the domain inputs.", 59 + }; 60 + 61 + return { ok: true }; 62 + };