Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

create-nextstream-app

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

create-nextstream-app

Scaffold a new Laravel and Next.js application

  • 0.0.8
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

Laravel Nextstream

A port of Laravel Jetstream to Next.js. All credit goes to Taylor Otwell and the Laravel team.

Installation

Scaffold the project

$ npx create-nextstream-app new my-app

Configure the database and serve the backend

# ensure you set your db credentials in backend/.env
$ cd backend
$ php artisan migrate
$ php artisan serve

Serve the frontend

$ cd frontend
$ npm run dev

By default your frontend will be available at http://localhost:3000 and your backend at http://localhost:8000

If you are not using the default localhost ports to serve either of your applications, ensure you update the SESSION_DOMAIN AND SANCTUM_STATEFUL_DOMAINS in your backend/.env file and the respective ones in frontend/.env.local.

Usage

Components

JetAppLayout

Acts as the base layout of your page. Includes top navigation + footer.

Accepts:

  • pageTitle: string - sets the head <title> tag
  • header?: string - optional, the white header right under the navigation
import JetAppLayout from './jet/layouts/app-layout';

function Component() {
  return (
    <JetAppLayout pageTitle="Dashboard">
      {/* Your page content here... */}
    </JetAppLayout>
  );
}
JetButton

Button with a few different appearances for use within your application. Accepts all normal button props with the addition of status.

import JetButton from './jet/components/button';

function Component() {
  return (
    <div>
      <JetButton>Primary</JetButton>
      <JetButton status={'secondary'}>Secondary</JetButton>
      <JetButton status={'danger'}>Danger</JetButton>
    </div>
  );
}
JetCheckbox

Styled checkbox. Takes same props as an HTML input.

import JetCheckbox from './jet/components/button';

function Component() {
  return (
    <div>
      <label htmlFor="remember" className="flex items-center">
        <JetCheckbox id="remember" name="remember" checked={checked} />
        <span className="ml-2 text-sm text-gray-600">Remember me</span>
      </label>
    </div>
  );
}
JetConfirmationModal
function Component() {
  const modal = useModal();

  return (
    <JetConfirmationModal
      {...modal.props}
      title={'Delete User?'}
      renderFooter={() => (
        <>
          <JetButton status={'secondary'} onClick={modal.close}>
            Nevermind
          </JetButton>
          <JetButton status={'danger'} className="ml-2">
            Delete
          </JetButton>
        </>
      )}
    >
      Are you sure you would like to delete this user?
    </JetConfirmationModal>
  );
}
JetDialogModal
function Component() {
  const modal = useModal();

  return (
    <JetDialogModal
      {...modal.props}
      title={'Your one-time key'}
      renderFooter={() => (
        <>
          <JetButton className="ml-2">Ok</JetButton>
        </>
      )}
    >
      abcdefg1234
    </JetDialogModal>
  );
}
JetDropdown

Dropdown powered by headless-ui.

function Component() {
  return (
    <JetDropdown renderTrigger={({ Trigger }) => <Trigger>Open</Trigger>}>
      {({ DropdownItem }) => (
        <div>
          <DropdownItem>
            <JetDropdownLink href={'/teams/1/settings'}>
              Team Settings
            </JetDropdownLink>
          </DropdownItem>
          <DropdownItem>
            <JetDropdownLink href={'/teams/new'}>
              Create New Team
            </JetDropdownLink>
          </DropdownItem>
        </div>
      )}
    </JetDropdown>
  );
}
JetFormActionSection

todo

JetFormSection

todo

JetGuestLayout

todo

JetInputError

todo

JetInput

todo

JetLabel

todo

JetModal

todo

JetSectionBorder

todo

JetSectionTitle

todo

Available Hooks

useUser

Returns the logged in user via the cookie.

import { useUser } from './jet/helpers/auth';

function Component() {
  const user = useUser();
}
useRefreshUser

Returns a function that you can call that will re-fetch the current user from the API and store it in the cookie.

import { useRefreshUser } from './jet/helpers/auth';

function Component() {
  const refreshUser = useRefreshUser();

  // e.g. you updated the users name now need to refresh them accross the app
  function onUserUpdated() {
    await http('user', {
      method: 'patch',
      body: {
        // ...
      },
    });
    refreshUser();
  }
}
useFeatures

Returns all of the jetstream features and whether or not they are enabled for your application based on your configuration set in your Laravel app.

import { useFeatures } from './jet/helpers/auth';

function Component() {
  // all booleans
  const {
    hasProfilePhotoFeatures,
    hasApiFeatures,
    hasAccountDeletionFeatures,
    canUpdateProfileInformation,
    updatePasswords,
    canManageTwoFactorAuthentication,
  } = useFeatures();
}
useModal

A convenience helper for storing modal state

import { useModal } from './jet/components/modal';

function Component() {
  const myModal = useModal();

  // to open
  // myModal.open()

  // to close
  // myModal.close()

  return (
    <div>
      <JetButton onClick={myModal.open}>Confirm</JetButton>

      <JetConfirmModal title={'Are you sure?'} {...myModal.props}>
        {/* ... */}
      </JetConfirmModal>
    </div>
  );
}
useConfirmPassword

Allows you to ask the user to confirm their password via a modal before performaning an action. Will only prompt the user if they haven't confirmed their password since the timeout set in your Laravel app.

Returns an object with the following keys:

  • loading - Set to true while the request to the API to confirm the password goes through
  • ConfirmPasswordModal - The component to render, takes no props
  • withPasswordConfirmation - Pass the function you want to run after the password has been confirmed. Returns a function that when called triggers the confirm password flow
import { useConfirmPassword } from './jet/components/confirm-password-modal';

function Component() {
  const {
    withPasswordConfirmation,
    ConfirmPasswordModal,
    loading,
  } = useConfirmPassword();

  return (
    <div>
      <JetButton
        onClick={withPasswordConfirmation(onSave)}
        disabled={isLoading}
      >
        Save
      </JetButton>

      <ConfirmPasswordModal />
    </div>
  );
}

Making HTTP Requests

Included is an http helper that wraps the global fetch function and allows you to make requests to your api (and external ones) on both the client side and server side. This abstraction makes it easy to call api routes with relative url's and automatically includes the required cookies in the proper context.

The signature for the function matches that of the global fetch

async function http(
  input: RequestInfo,
  init?: Init,
): {
  ok: boolean;
  response: Response; // raw fetch response
  data: any | null; // If ok and response type was JSON, this is the parsed body
  errors: any | null; // If not ok and response type was JSON, this is the parsed body
};

To make a request inside a React component (client side):

// example GET request
async function getUser() {
  const { ok, data } = await http('user');
}

// example POST request
async function submit() {
  const { ok, data } = await http('user/password', {
    method: 'post',
    body: JSON.stringify({ old_password: 'abcd', password: 'defg' }),
  });
}

Making requests during SSR is almost exactly the same except you need to remember to include the req object from the context so we can forward along the cookie:

export const getServerSideProps: GetServerSideProps = ({ req, res }) => {
  const { ok, response, data, errors } = await http('user', { req });
  if (!ok) {
    res.statusCode = 500;
    res.end();
  }
  return {
    props: {
      user: data.user,
    },
  };
};

The http helper requires you to format your data before sending it (e.g. in a POST request) so that it doesn't make the wrong assumption.

That means that if you are wanting to send JSON, you need to manually stringify it yourself as you would in a fetch call.

async function onSubmit() {
  const { ok, response, data, errors } = await http('api/my-post-request', {
    method: 'post',
    body: JSON.stringify(data),
  });
}

Which also means you can pass formdata if you want (for file uploads, etc) and it will get handled appropriately without needing to specify any additional headers.

async function onSubmit() {
  const formData = new FormData();
  formData.append('photo', myFile, myFile.name);
  const { ok, response, data, errors } = await http('api/my-post-request', {
    method: 'post',
    body: formData,
  });
}

Writing API Endpoints

Endpoints can be built as normal the Laravel way. Make sure to place them in routes/api.php to ensure they are handled properly with CORS, and if you need them to be protected by authentication ensure they are wrapped in the auth:sanctum middleware.

Protecting Frontend Routes

Included are two helper functions that make it easy to make routes "guest" only or "logged in" only.

To use these, simply export them as your getServerSideProps function.

// use this if you want the page visible to only guests
export const getServerSideProps = redirectIfAuthenticated();

// use this if you need to be logged in to view the page
export const getServerSideProps = redirectIfGuest();

You can also provide a function that gets executed if you would still like to add your own logic that gets ran after the authentication check.

export const getServerSideProps = redirectIfGuest(({ req }) => {
  const { ok, data } = await http('user', { req });
  // ...
  return {
    props: {
      user: data.user,
    },
  };
});

Forms

All included forms make use of the react-hook-form library. To find out more, visit their website at https://react-hook-form.com/.

Roadmap

  • User authentication
  • Two factor authentication
  • Password recovery
  • Api keys
  • Profile photos
  • User deletion
  • Team support
  • Browser sessions
  • Email verification
  • Project initializer
  • Tests
  • Terms and conditions / privacy policy
  • Documentation (http, components, auth, etc)
  • Organize jet files + providers

Keywords

FAQs

Package last updated on 15 Mar 2021

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc