Creating Subscriptions Management in Headless

Hello,
So I have succesfully created in our hydrogen store a way to create subscriptions in our PDP that hits the Shopify Subscriptions endpoint. Everything appears in the subscriptions app and can be managed there. However, I want to allow the customer a way to manage them within their account page. I have created an account.subscriptions.jsx route and I’m really close, just having issues with the customer_access_token and querying their data. Though the order history page pulls everything just fine. Please advise, below is my account.subscriptions.jsx

import { json, redirect } from '@shopify/remix-oxygen';
import { useLoaderData, Form, useActionData } from '@remix-run/react';
import { useState } from 'react';

// Admin API query for subscription contracts
const SUBSCRIPTION_CONTRACTS_QUERY = `#graphql
  query SubscriptionContracts($customerId: ID!) {
    subscriptionContracts(first: 10, query: "customer_id:$customerId") {
      edges {
        node {
          id
          status
          nextBillingDate
          customer {
            id
            firstName
            lastName
          }
          billingPolicy {
            interval
            intervalCount
          }
          deliveryPolicy {
            interval
            intervalCount
          }
          lines(first: 5) {
            edges {
              node {
                productId
                variantId
                title
                quantity
              }
            }
          }
        }
      }
    }
  }
`;

// Admin API mutation to cancel a subscription
const CANCEL_SUBSCRIPTION_MUTATION = `#graphql
  mutation SubscriptionContractUpdate($contractId: ID!) {
    subscriptionContractUpdate(
      contractId: $contractId
      contract: { status: CANCELLED }
    ) {
      subscriptionContract {
        id
        status
      }
      userErrors {
        field
        message
      }
    }
  }
`;

export async function loader({ context, request }) {
  const { session, admin } = context;

  console.log('Session contents:', session.data);
  const customerId = session.get('customerId');
  const accessToken = session.get('customer_access_token');

  console.log('Loader - Customer ID:', customerId);
  console.log('Loader - Access Token:', accessToken);

  if (!accessToken || !customerId) {
    console.log('Redirecting to login - Missing session data');
    return redirect('/account/login');
  }

  try {
    const customerGid = `gid://shopify/Customer/${customerId}`;
    const result = await admin.graphql(SUBSCRIPTION_CONTRACTS_QUERY, {
      variables: { customerId: customerGid },
    });

    const data = await result.json();
    console.log('Raw GraphQL response:', data); // Debug full response
    const subscriptions = data?.data?.subscriptionContracts?.edges || [];
    console.log('Subscriptions fetched:', subscriptions);
    return json({ subscriptions });
  } catch (error) {
    console.error('Error fetching subscriptions:', error);
    return json({ subscriptions: [], error: 'Unable to fetch subscriptions' }, { status: 500 });
  }
}

export async function action({ request, context }) {
  const { admin } = context;
  const formData = await request.formData();
  const contractId = formData.get('contractId');

  if (!contractId) {
    return json({ error: 'No subscription ID provided' }, { status: 400 });
  }

  try {
    const result = await admin.graphql(CANCEL_SUBSCRIPTION_MUTATION, {
      variables: { contractId },
    });

    const data = await result.json();
    const { subscriptionContract, userErrors } = data.data.subscriptionContractUpdate;

    if (userErrors?.length > 0) {
      return json({ error: userErrors[0].message }, { status: 400 });
    }

    if (subscriptionContract?.status === 'CANCELLED') {
      return json({ success: `Subscription ${contractId} cancelled successfully` });
    }

    return json({ error: 'Failed to cancel subscription' }, { status: 500 });
  } catch (error) {
    console.error('Error cancelling subscription:', error);
    return json({ error: 'An error occurred while cancelling the subscription' }, { status: 500 });
  }
}

export default function SubscriptionManagement() {
  const { subscriptions } = useLoaderData();
  const actionData = useActionData();
  const [message, setMessage] = useState('');

  if (actionData?.success) {
    setTimeout(() => setMessage(actionData.success), 100);
  } else if (actionData?.error) {
    setTimeout(() => setMessage(actionData.error), 100);
  }

  return (
    <div className="account-subscriptions">
      <h1>Your Subscriptions</h1>
      {message && <p className="text-center text-sm mt-2">{message}</p>}
      {subscriptions.length === 0 ? (
        <p>No active subscriptions found.</p>
      ) : (
        <ul className="subscription-list">
          {subscriptions.map(({ node: subscription }) => (
            <li
              key={subscription.id}
              className="subscription-item border p-4 rounded my-4"
            >
              <p>
                <strong>Subscription ID:</strong> {subscription.id.split('/').pop()}
              </p>
              <p>
                <strong>Status:</strong> {subscription.status}
              </p>
              <p>
                <strong>Next Billing Date:</strong>{' '}
                {new Date(subscription.nextBillingDate).toLocaleDateString()}
              </p>
              <p>
                <strong>Billing:</strong> Every {subscription.billingPolicy.intervalCount}{' '}
                {subscription.billingPolicy.interval.toLowerCase()}
              </p>
              <p>
                <strong>Delivery:</strong> Every {subscription.deliveryPolicy.intervalCount}{' '}
                {subscription.deliveryPolicy.interval.toLowerCase()}
              </p>
              <div>
                <strong>Items:</strong>
                <ul>
                  {subscription.lines.edges.map(({ node: line }) => (
                    <li key={line.variantId}>
                      {line.title} (Qty: {line.quantity})
                    </li>
                  ))}
                </ul>
              </div>
              {subscription.status === 'ACTIVE' && (
                <Form method="post">
                  <input type="hidden" name="contractId" value={subscription.id} />
                  <button
                    type="submit"
                    className="bg-red-600 text-white px-4 py-2 rounded hover:bg-red-700 mt-2"
                  >
                    Cancel Subscription
                  </button>
                </Form>
              )}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

Thank you!

Hi, are you testing with a logged in user? Canceling subscription is only allowed for logged in users.