aws-amplify / amplify-ui

Amplify UI is a collection of accessible, themeable, performant React (and more!) components that can connect directly to the cloud.
https://ui.docs.amplify.aws
Apache License 2.0
793 stars 262 forks source link

Ability to customize SignUp component (Add a checkbox) #4948

Open shivjoshi1996 opened 6 months ago

shivjoshi1996 commented 6 months ago

On which framework/platform would you like to see this feature implemented?

React Native

Which UI component is this feature-request for?

Authenticator

Please describe your feature-request in detail.

Hi there,

I'm currently using the React Native Authenticator component, and I'm trying to implement a sign up page with a T&C's checkbox, similar to the one described in the Amplify React docs here, but I'm having some trouble with figuring out if this is possible with the React Native package.

I've tried a couple of ways:

  1. Trying to override the SignUp component using the subcomponent override method described here.

When I try to do something like this, the checkbox doesn't show below the form fields. It does show up if I move it outside of the Authenticator component. If I remove the Authenticator component the Sign Up form fields fail to show up. Am I doing something wrong? Or is this not currently possible with the React Native package?

Example code for the custom SignUp component:

const MySignUp = () => {
  return (
    <View>
      <Authenticator>
        <Authenticator.SignUp.FormFields />
        <CheckBox checked title="I agree to the terms and conditions" />
      </Authenticator>
    </View>
  );
};

Passed into the Authenticator component, in my root _layout file.

<Authenticator.Provider>
    <Authenticator
          components={{
            SignUp: MySignUp,
          }}>
         <Slot />
    </Authenticator>
</Authenticator.Provider>
  1. Adding a form field to SignUp as described here

The fields array doesn't support a type of checkbox so I'm not sure if this way is even feasible.

Does anyone have any thoughts on how I would achieve this?

Thanks!

Please describe a solution you'd like.

We love contributors! Is this something you'd be interested in working on?

shivjoshi1996 commented 6 months ago

Update on this, I managed to get this kinda working. I also realized I wasn't passing {...props} into the Custom component. The example in the docs doesn't show this, and it would be nice to add this there.

Here's the current WIP code:

Root _layout.tsx

<Authenticator.Provider>
        <Authenticator
          components={{
            SignUp: (props) => {
              return <MySignUp {...props} />;
            },
          }}
          services={{
            handleSignUp: ({ username, password, options }: SignUpInput) =>
              signUp({
                username,
                password,
              }),
          }}
        >
          <Slot />
        </Authenticator>
      </Authenticator.Provider>

Custom SignUp component

const MySignUp = (props) => {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [isTermsAccepted, setIsTermsAccepted] = useState(false);
  const { handleSubmit, toSignIn } = props;

  const handleSignUp = async () => {
    if (!isTermsAccepted) {
      console.log("Terms not accepted");
      return;

    try {
      console.log("Signing Up...");
      await signUp({ username, password });
    } catch (error) {
      console.error("Error signing Up:", error);
    }
  };

  return (
    <View>
      <Input
        placeholder="Email"
        onChangeText={(text) => setUsername(text)}
        value={username}
        autoComplete="email"
      />
      <Input
        placeholder="Password"
        secureTextEntry={true}
        onChangeText={(text) => setPassword(text)}
        value={password}
      />
      <Input
        placeholder="Confirm Password"
        secureTextEntry={true}
        onChangeText={(text) => setConfirmPassword(text)}
        value={confirmPassword}
      />
      <CheckBox
        title="I have read the Terms and Conditions"
        checked={isTermsAccepted}
        onPress={() => setIsTermsAccepted(!isTermsAccepted)}
      />

      <Button
        onPress={handleSignUp}
      >
        Sign Up
      </Button>
      <Button onPress={toSignIn}>Create an account</Button>
    </View>
  );
};

A couple of questions I have:

  1. Is there a way I can re-use the Sign Up Fields? I tried using <Authenticator.SignUp.FormFields /> in my custom component, and it rendered the fields fine, but I'm not sure how to get the values from those fields when calling the signIn function.
  2. If the above answer is no, then is there a way I can easily use the same styling used for the rest of the Authenticator screens? The only custom screen I have is signUp. I want to make sure it matches the other Authenticator UI, is there an good way to do this?
  3. I also wasn't able to use handleSubmit in my handleSignUp call, as I've seen in this ticket: https://github.com/aws-amplify/amplify-ui/issues/4939, and had to use await signUp({ username, password }); instead, although I know this isn't the way to go. Any idea why handleSubmit won't work? Is there a piece I'm missing here?

I'm still trying to figure out how to use this library effectively, so if there is a better way to do any of this, please let me know! Thanks.