Skip to content
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

Co-Location with dynamic variable in URL not seeming to work as intended #404

Closed
1 task done
thebreadcat opened this issue Jul 9, 2024 · 3 comments
Closed
1 task done

Comments

@thebreadcat
Copy link

thebreadcat commented Jul 9, 2024

Describe the bug

Issue Summary:
I'm using Frog + Next.js to host a website where the main url when shared on FC would render the default frame state (working fine.). When sharing /profile/:username URLs it should render the frame with the username passed in to fetch the data and render a different first frame (working fine locally and on supercast.xyz.). This DOES NOT work currently on Warpcast. I have tried many different things but feel i'm missing something entirely after days of trying to debug this. My current project is pretty far built so I'm trying to avoid sharing huge chunks of code but I'll share the most relevant parts.

It's rendering the metadata fine (i think) when I console.log it.:

 {
  'fc:frame': 'vNext',
  'fc:frame:image:aspect_ratio': '1:1',
  'fc:frame:image': 'https://faniofull.framesframes.xyz/api/existing-image/19',
  'og:image': 'https://faniofull.framesframes.xyz/api/existing-image/19',
  'og:title': 'Fan.io | FanPage',
  'fc:frame:post_url': 'https://faniofull.framesframes.xyz/api?initialPath=%252Fapi&previousButtonValues=%2523A_19%252C19%252C_l%252C_l',
  'fc:frame:button:1': '⬆️',
  'fc:frame:button:1:action': 'post',
  'fc:frame:button:1:target': 'https://faniofull.framesframes.xyz/api/existing/4?initialPath=%252Fapi&previousButtonValues=%2523A_19%252C19%252C_l%252C_l',
  'fc:frame:button:2': '⬇️',
  'fc:frame:button:2:action': 'post',
  'fc:frame:button:2:target': 'https://faniofull.framesframes.xyz/api/existing/2?initialPath=%252Fapi&previousButtonValues=%2523A_19%252C19%252C_l%252C_l',
  'fc:frame:button:3': 'test',
  'fc:frame:button:3:action': 'link',
  'fc:frame:button:3:target': 'test.com',
  'fc:frame:button:4': 'Fan Page',
  'fc:frame:button:4:action': 'link',
  'fc:frame:button:4:target': 'https://faniosite.framesframes.xyz/profile/breadcat',
  'frog:version': '0.12.3'
}

But it shows up as "not a valid frame"

/profile/[id]/page.tsx:

  import { headers } from 'next/headers'
  import type { Metadata } from 'next'
  import { getFrameMetadata, isFrameRequest } from 'frog/next'
  import { SuspendedComponent } from '../../suspense-component';
  
  export async function generateMetadata(props: any): Promise<Metadata> {
    const url = process.env.NEXT_PUBLIC_URL || 'http://localhost:3000'
    const frameMetadata = await getFrameMetadata(`${url}/api?username=${props.params.id}`);
    console.log('meta', frameMetadata);
    return {
      other: frameMetadata,
    }
  }
  export default function Page(props: any) {
    const { id } = props.params;
    if (isFrameRequest(headers())) return null
    console.log('we failed being a frame');   // <-- this fires on /profile/username - does NOT fire on just / or /api
    return <SuspendedComponent id={id.toString()} />
  }

main route:

app.frame('/', async (c) => {
  const { buttonValue, inputText, status } = c;
  const frameId  = c.req.query('frameId') || false;
  const fid      = c.req.query('fid') || false;
  const wallet   = c.req.query('wallet') || false;
  const username = c.req.query('username') || false;
  console.log('user', username);
  let existingFan: Fan | false = false;
  let activeLink = 1;
  let fanColor = '#E75F58';
  app.imageAspectRatio = '1.91:1';
  const colorMap: { [key in Fan['color']]: string } = {
    red: '#FF0000',
    yellow: '#FFFF00',
    green: '#008000',
    blue: '#0000FF',
    purple: '#800080',
    black: '#000000',
  };
  let intents: any = [];
  try {
    if (frameId) {
      existingFan = await getFanById(frameId);
    } else if (wallet) {
      existingFan = await getFanByWallet(wallet);
    } else if (fid) {
      existingFan = await getFanByFid(fid);
    } else if (username) {
      existingFan = await getFanByUsername(username);
    }
  } catch (error) {
    console.error('Error fetching fan:', error);
  }
  console.log(existingFan);

  let imageElements = (
    <div style={{ display: 'flex', flexDirection: 'column', backgroundColor: '#1A1A1A', flex: '1', alignItems: 'center', justifyContent: 'space-between', height: '100vh' }}>
      <div style={{ display: 'flex', flexDirection: 'column', fontFamily: 'font-["Inter"]', color: 'white', padding: '4rem', justifyContent: 'center' }}>
        <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginTop: '2rem', marginBottom: '4rem' }}>
          <img src={process.env.NEXT_PUBLIC_URL + '/fan-frame-logo.png'} style={{ width: '150px', height: '150px' }} />
          <span style={{ borderRadius: '8rem', padding: '1rem 1.25rem', backgroundColor: '#454545', fontSize: '30', fontFamily: 'font-["Inter"]' }}>fan.io/yourname</span>
        </div>
        <span style={{ color: '#fff', fontSize: 56, marginBottom: '1rem', fontWeight: 'bold' }}>
          Deploy Your FAN Page
        </span>
        <span style={{ color: '#fff', fontSize: 42, marginBottom: '1rem', fontWeight: '300' }}>
          Create a hub for your web3 identity directly in this frame. Share your links and showcase your projects on your personalized website. Get started now! ⬇️
        </span>
      </div>
    </div>
  ) as any;

  if (existingFan) {
    app.imageAspectRatio = '1:1';
    imageElements = '/existing-image/' + existingFan.id.toString();
    intents.push(<Button value={existingFan.id.toString()} action="/existing/4">⬆️</Button>);
    intents.push(<Button value={existingFan.id.toString()} action="/existing/2">⬇️</Button>);
    intents.push(
      <Button.Link href={String(existingFan[`link_${activeLink}_url` as keyof Fan] || '')}>
        {String(existingFan[`link_${activeLink}_name` as keyof Fan] || '')}
      </Button.Link>
    );
    intents.push(
      <Button.Link href={'https://faniosite.framesframes.xyz/profile/' + existingFan.username}>Fan Page</Button.Link>
    );
  } else {
    intents.push(<Button value={frameId.toString()} action="/start">Get Started</Button>);
  }
  return c.res({
    image: imageElements,
    intents: intents,
  });
});

image handler for the dynamic part:

app.image('/existing-image/:id', async (c) => {
  const id = extractLastValue(c.req.path);
  let existingFan: Fan | false = await getFanById(id);
  const colorMap: { [key in Fan['color']]: string } = {
    red: '#FF0000',
    yellow: '#FFFF00',
    green: '#008000',
    blue: '#0000FF',
    purple: '#800080',
    black: '#000000',
  };
  var fanColor: string = '#E75F58';
  let bio;
  if(existingFan){
    app.imageAspectRatio = '1:1';
    const color = existingFan.color as keyof typeof colorMap;
    fanColor = colorMap[color] || '#E75F58';
    bio = existingFan.bio ? existingFan.bio.replace(/<[^>]*>?/gm, '') : '';
  }
  return c.res({
    headers: {
      'Cache-Control': 'max-age=0'
    },
    image: (
      <div style={{ display: 'flex', flexDirection: 'column', height: '100vh', fontFamily: 'font-["Inter"]', color: 'white', backgroundColor: '#1A1A1A' }}>
        <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', alignItems: 'center', width: '100vw' }}>
          {fanColor && existingFan && (
            <div style={{ backgroundColor: fanColor, height: '6rem', width: '100%', display: 'flex', justifyContent: 'flex-end', flexDirection: 'column', alignItems: 'center' }}>
              {existingFan.username && existingFan.avatar && (
                <img style={{ borderRadius: '50%', border: '10px solid #1A1A1A', width: '7.25rem', height: '7.25rem', marginBottom: '-4rem' }} src={existingFan.avatar} alt={`${existingFan.username}'s avatar`} />
              )}
            </div>
          )}
          {existingFan && (
            <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', marginTop: '5rem' }}>
              <h1 style={{ fontSize: 26, padding: 0, margin: 0, textTransform: 'capitalize' }}>{existingFan.username}</h1>
              {bio && (
                <p style={{ padding: '1rem 2rem', paddingTop: '0', fontSize: 16, textAlign: 'center', marginBottom: '2rem', width: '50vw' }}>
                  {truncateText(bio, 155)}
                </p>
              )}
            </div>
          )}
          <div style={{ display: 'flex', flexDirection: 'column' }}>
            {existingFan && existingFan.link_1_name && existingFan.link_1_url && (
              <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'center', border: `4px solid ${fanColor}`, textTransform: 'uppercase', backgroundColor: '#1D1D1D', fontSize: 20, width: '35vw', padding: '0.75rem 1rem', fontWeight: '300', marginBottom: '1rem', borderRadius: '8rem' }}>
                {truncateText(existingFan.link_1_name, 12)}
              </div>
            )}
            {existingFan && existingFan.link_2_name && existingFan.link_2_url && (
              <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'center', border: '2px solid #2D2D2D', textTransform: 'uppercase', backgroundColor: '#1D1D1D', fontSize: 20, width: '35vw', padding: '0.75rem 1rem', fontWeight: '300', marginBottom: '1rem', borderRadius: '8rem' }}>
                {truncateText(existingFan.link_2_name, 12)}
              </div>
            )}
            {existingFan && existingFan.link_3_name && existingFan.link_3_url && (
              <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'center', border: '2px solid #2D2D2D', textTransform: 'uppercase', backgroundColor: '#1D1D1D', fontSize: 20, width: '35vw', padding: '0.75rem 1rem', fontWeight: '300', marginBottom: '1rem', borderRadius: '8rem' }}>
                {truncateText(existingFan.link_3_name, 12)}
              </div>
            )}
            {existingFan && existingFan.link_4_name && existingFan.link_4_url && (
              <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'center', border: '2px solid #2D2D2D', textTransform: 'uppercase', backgroundColor: '#1D1D1D', fontSize: 20, width: '35vw', padding: '0.75rem 1rem', fontWeight: '300', marginBottom: '1rem', borderRadius: '8rem' }}>
                {truncateText(existingFan.link_4_name, 12)}
              </div>
            )}
          </div>
        </div>
      </div>
    )
  })
});

Again i've tried a ton of things but it seems like either i'm missing some core understanding of how this should work or dynamic variables for co-location may be off.

Semi-unrelated, I saw a few people struggling with co-location so I made an example that works well for non-dynamic variables being passed in here: Co-Location x Frog

Link to Minimal Reproducible Example

https://github.com/thebreadcat/coloco-frog-with-args

Steps To Reproduce

  1. Deploy build to Vercel
  2. Access URL and use the Warpcast Debugger with the URL
  3. Frame works as intended.
  4. Add /profile/breadcat to url in debugger
  5. Get "Not a valid Frame"

Frog Version

0.12.3

TypeScript Version

5.5.3

Check existing issues

Anything else?

Love Frog! Thanks for all you all do!

@tmm tmm added the Needs Reproduction Misc: Needs Reproduction label Jul 9, 2024
Copy link
Contributor

github-actions bot commented Jul 9, 2024

Hello @thebreadcat.

Please provide a minimal reproduction using StackBlitz, TypeScript Playground (for type issues), or a separate minimal GitHub repository.

Minimal reproductions are required as they save us a lot of time reproducing your config & environment, and trying to reproduce your issue. See Why reproductions are required.

Please reopen this issue when a reproduction is added.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 9, 2024
@thebreadcat
Copy link
Author

Updated with minimal Repo: https://github.com/thebreadcat/coloco-frog-with-args

@dalechyn dalechyn reopened this Jul 17, 2024
@dalechyn dalechyn removed the Needs Reproduction Misc: Needs Reproduction label Jul 18, 2024
@dalechyn
Copy link
Collaborator

@thebreadcat, I think we've resolved the issue and it was invalid URL, test.com.

All URLs must start with HTTP/S protocol prefix.

If there's still an issue, please re-open.

@dalechyn dalechyn closed this as not planned Won't fix, can't repro, duplicate, stale Jul 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants