-
Notifications
You must be signed in to change notification settings - Fork 7
Vincent 2.0 Dashboard #440
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
009cf0e
5bad8e0
d0e9533
64df637
31e8ae6
be0179b
dd93c8f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,27 +1,11 @@ | ||
| VITE_VINCENT_DATIL_CONTRACT=0xa3a602F399E9663279cdF63a290101cB6560A87e | ||
| VITE_DATIL_PKP_CONTRACT=0x487A9D096BB4B7Ac1520Cb12370e31e677B175EA | ||
|
|
||
| VITE_STYTCH_PUBLIC_TOKEN= | ||
| VITE_STYTCH_PROJECT_ID= | ||
|
|
||
| VITE_LIT_PAYER_SECRET_KEY= | ||
| VITE_LIT_RELAY_API_KEY= | ||
| VITE_VINCENT_YELLOWSTONE_RPC=https://yellowstone-rpc.litprotocol.com/ | ||
|
|
||
| VITE_WALLETCONNECT_PROJECT_ID= | ||
|
|
||
| VITE_JWT_EXPIRATION_MINUTES=2160 | ||
|
|
||
| VITE_GAS_BUFFER_DIVISOR=10 | ||
|
|
||
| VITE_VINCENT_YIELD_APPID=2353287477 | ||
| VITE_VINCENT_YIELD_MINIMUM_DEPOSIT=50 | ||
|
|
||
| VITE_LIT_FEATURE_ENV= | ||
|
|
||
| VITE_DASHBOARD_URL=http://localhost:5173 | ||
| VITE_VINCENT_BASE_SEPOLIA_RPC= | ||
|
|
||
| VITE_ENV=development | ||
|
|
||
| VITE_LIT_TOTAL_MANAGED=340 | ||
| VITE_TOTAL_APPS= | ||
| VITE_TOTAL_ABILITIES= | ||
|
|
||
| VITE_FEATURED_APP_IDS= | ||
| VITE_OFFICIAL_APP_IDS= |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,55 +10,71 @@ import { Button } from '@/components/shared/ui/button'; | |
| import { | ||
| TextField, | ||
| LongTextField, | ||
| ArrayField, | ||
| ImageUploadField, | ||
| } from '@/components/developer-dashboard/form-fields'; | ||
| import { DeploymentStatusSelectField } from '@/components/developer-dashboard/form-fields/array/DeploymentStatusSelectField'; | ||
| import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme'; | ||
| import { theme, fonts } from '@/lib/themeClasses'; | ||
| import { extractErrorMessage } from '@/utils/developer-dashboard/app-forms'; | ||
|
|
||
| const { appDoc } = docSchemas; | ||
|
|
||
| const { | ||
| name, | ||
| description, | ||
| contactEmail, | ||
| appUserUrl, | ||
| logo, | ||
| redirectUris, | ||
| deploymentStatus, | ||
| delegateeAddresses, | ||
| } = appDoc.shape; | ||
| const { appId, name, description, contactEmail, appUrl, logo, deploymentStatus } = appDoc.shape; | ||
|
|
||
| // Schema for creating a new app (appId will be generated on-chain) | ||
| export const CreateAppSchema = z | ||
| .object({ | ||
| name, | ||
| description, | ||
| contactEmail, | ||
| appUserUrl, | ||
| appUrl, | ||
| logo, | ||
| deploymentStatus, | ||
| }) | ||
| .strict(); | ||
|
|
||
| // Schema for adding existing on-chain app to registry | ||
| export const CreateAppWithIdSchema = z | ||
| .object({ | ||
| appId, | ||
| name, | ||
| description, | ||
| contactEmail, | ||
| appUrl, | ||
| logo, | ||
| redirectUris, | ||
| deploymentStatus, | ||
| delegateeAddresses, | ||
| }) | ||
| .strict(); | ||
|
|
||
| export type CreateAppFormData = z.infer<typeof CreateAppSchema>; | ||
| export type CreateAppWithIdFormData = z.infer<typeof CreateAppWithIdSchema>; | ||
|
|
||
| interface CreateAppFormProps { | ||
| onSubmit: (data: CreateAppFormData) => Promise<void>; | ||
| onSubmit: (data: CreateAppFormData | CreateAppWithIdFormData) => Promise<void>; | ||
| isSubmitting?: boolean; | ||
| /** | ||
| * When provided, the form is used for recovery: syncing an app that exists | ||
| * on-chain but failed to sync to the registry during initial registration. | ||
| */ | ||
| existingAppId?: number; | ||
| onSuccess?: () => void; | ||
| } | ||
|
|
||
| export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormProps) { | ||
| export function CreateAppForm({ | ||
| onSubmit, | ||
| isSubmitting = false, | ||
| existingAppId, | ||
| onSuccess, | ||
| }: CreateAppFormProps) { | ||
| const [submitError, setSubmitError] = useState<string | null>(null); | ||
| const [submitSuccess, setSubmitSuccess] = useState(false); | ||
|
|
||
| const form = useForm<CreateAppFormData>({ | ||
| resolver: zodResolver(CreateAppSchema), | ||
| // Use different schema based on whether we have an existing app ID | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An app can be registered only once so what are we exactly checking for the existing appId?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is useful for when the App registration (in the registry) has failed. There is a recovery flow to create the App document in the event of that happening, but I didn't have the chance to implement a recovery flow for the AppVersionAbility documents. That would look like reading the app's version 1 from on-chain, reading the IPFS CIDs, and then finding their matches in our database. We'd then create the AppVersionAbility documents on the developer's behalf. cc: @glitch003 (just to let you know)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you create a ticket for the remaining task @awisniew207 |
||
| const schema = existingAppId ? CreateAppWithIdSchema : CreateAppSchema; | ||
|
|
||
| const form = useForm<CreateAppFormData | CreateAppWithIdFormData>({ | ||
| resolver: zodResolver(schema), | ||
| defaultValues: { | ||
| redirectUris: [''], | ||
| delegateeAddresses: [''], | ||
| ...(existingAppId && { appId: existingAppId }), | ||
| deploymentStatus: 'dev', | ||
| }, | ||
| }); | ||
|
|
@@ -74,12 +90,15 @@ export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormP | |
| formState: { errors }, | ||
| } = form; | ||
|
|
||
| const handleFormSubmit = async (data: CreateAppFormData) => { | ||
| const handleFormSubmit = async (data: CreateAppFormData | CreateAppWithIdFormData) => { | ||
| setSubmitError(null); | ||
| setSubmitSuccess(false); | ||
| try { | ||
| await onSubmit(data); | ||
| setSubmitSuccess(true); | ||
| if (onSuccess) { | ||
| onSuccess(); | ||
| } | ||
| } catch (error) { | ||
| console.error('Failed to create app:', error); | ||
| setSubmitError(extractErrorMessage(error, 'Failed to create app')); | ||
|
|
@@ -129,10 +148,10 @@ export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormP | |
| /> | ||
|
|
||
| <TextField | ||
| name="appUserUrl" | ||
| name="appUrl" | ||
| register={register} | ||
| error={errors.appUserUrl?.message} | ||
| label="App User URL" | ||
| error={errors.appUrl?.message} | ||
| label="App URL" | ||
| placeholder="https://yourapp.com" | ||
| required | ||
| /> | ||
|
|
@@ -163,31 +182,6 @@ export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormP | |
| </div> | ||
| </div> | ||
|
|
||
| {/* Full Width Fields */} | ||
| <div className="space-y-6"> | ||
| <ArrayField | ||
| name="redirectUris" | ||
| register={register} | ||
| error={errors.redirectUris?.message} | ||
| errors={errors} | ||
| control={control} | ||
| label="Redirect URIs" | ||
| placeholder="https://yourapp.com/callback" | ||
| required | ||
| /> | ||
|
|
||
| <ArrayField | ||
| name="delegateeAddresses" | ||
| register={register} | ||
| error={errors.delegateeAddresses?.message} | ||
| errors={errors} | ||
| control={control} | ||
| label="Delegatee Addresses" | ||
| placeholder="0x1234567890123456789012345678901234567890" | ||
| required | ||
| /> | ||
| </div> | ||
|
|
||
| {/* Status Messages */} | ||
| {submitError && ( | ||
| <div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800"> | ||
|
|
@@ -200,7 +194,9 @@ export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormP | |
| <div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800"> | ||
| <CheckCircle className="h-4 w-4 text-green-600 dark:text-green-400 flex-shrink-0" /> | ||
| <span className="text-sm text-green-600 dark:text-green-400"> | ||
| App created successfully! | ||
| {existingAppId | ||
| ? 'App synced to registry successfully!' | ||
| : 'App created successfully!'} | ||
| </span> | ||
| </div> | ||
| )} | ||
|
|
@@ -211,7 +207,13 @@ export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormP | |
| style={{ backgroundColor: theme.brandOrange }} | ||
| disabled={isSubmitting} | ||
| > | ||
| {isSubmitting ? 'Creating App...' : 'Create App'} | ||
| {isSubmitting | ||
| ? existingAppId | ||
| ? 'Syncing to Registry...' | ||
| : 'Creating App...' | ||
| : existingAppId | ||
| ? 'Sync to Registry' | ||
| : 'Create App'} | ||
| </Button> | ||
| </div> | ||
| </form> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.