<file_sep>import React,{useState,useEffect} from 'react';
import { Auth, Hub } from "aws-amplify";

export const IdentityContext = React.createContext({});


const IdentityProvider = props => {
  const [user, setUser] = useState(null)

  useEffect(() => {
    Hub.listen("auth", ({ payload: { event } }) => {
      switch (event) {
        case "signIn":
        case "cognitoHostedUI":
          getUser().then(userData => setUser(userData))
          break
        case "signOut":
          setUser(null)
          break
        case "signIn_failure":
        case "cognitoHostedUI_failure":
          break
          default:
            console.log('something went wrong')
      }
    })

    getUser().then(userData => {
      setUser(userData)
      console.log("Signed In:", userData)
    })
  }, [])

  function getUser() {
    return Auth.currentAuthenticatedUser()
      .then(userData => userData)
      .catch(() => console.log("Not signed in"))
  }


  return (
    <IdentityContext.Provider value={{ user }}>
      {props.children}
    </IdentityContext.Provider>
  )
};

export default IdentityProvider;<file_sep>import React, { useContext } from "react";
import { Flex, NavLink } from "theme-ui";
import { Link } from "gatsby";
import { IdentityContext } from "../../Identity-Context";
import { Auth} from "aws-amplify";

const Navbar = () => {
  const { user } = useContext(IdentityContext);
  return (
    <Flex as="nav">
      <NavLink as={Link} to="/" p={2}>
        Home
      </NavLink>
      {user && <NavLink as={Link} to="/app" p={2}>Dashboard</NavLink>}
      {user && (
        <NavLink  sx={{ cursor: 'pointer' }} p={2} onClick={() => Auth.signOut()}>
          Logout {user.signInUserSession.idToken.payload.given_name}
        </NavLink>
      )}
    </Flex>
  );
};

export default Navbar;
<file_sep>import * as cdk from '@aws-cdk/core';
import * as lambda from '@aws-cdk/aws-lambda';
import * as appsync from '@aws-cdk/aws-appsync';
import * as events from '@aws-cdk/aws-events';
import * as eventsTargets from '@aws-cdk/aws-events-targets';
import * as dynamoDB from '@aws-cdk/aws-dynamodb';
import * as cognito from '@aws-cdk/aws-cognito';
import * as cloudfront from "@aws-cdk/aws-cloudfront";
import * as origins from "@aws-cdk/aws-cloudfront-origins";
import * as s3 from "@aws-cdk/aws-s3";
import * as s3deploy from "@aws-cdk/aws-s3-deployment";
import { requestTemplate, responseTemplate, EVENT_SOURCE } from '../utils/appsync-request-response';

export class BackendStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    //Here we define our Authentication via google
    const userPool = new cognito.UserPool(this, "TodosGoogleUserPool", {
      selfSignUpEnabled: true,
      accountRecovery: cognito.AccountRecovery.EMAIL_ONLY,
      userVerification: { emailStyle: cognito.VerificationEmailStyle.CODE },
      autoVerify: { email: true },
      standardAttributes: {
        email: {
          required: true,
          mutable: true,
        },
      },
    });

    const provider = new cognito.UserPoolIdentityProviderGoogle(this, "googleProvider",
      {
        userPool: userPool,
        clientId: "946189751283-qar9hmgh34n2k95g99bj5t21q92u612u.apps.googleusercontent.com",
        clientSecret: "<KEY>", // Google Client Secret
        attributeMapping: {
          email: cognito.ProviderAttribute.GOOGLE_EMAIL,
          givenName: cognito.ProviderAttribute.GOOGLE_GIVEN_NAME,
          phoneNumber: cognito.ProviderAttribute.GOOGLE_PHONE_NUMBERS,
        },
        scopes: ["profile", "email", "openid"],
      }
    );
    userPool.registerIdentityProvider(provider);
    const userPoolClient = new cognito.UserPoolClient(this, "todoamplifyClient", {
      userPool,
      oAuth: {
        callbackUrls: ["https://dd7ec0n7fuvn7.cloudfront.net/"], // This is what user is allowed to be redirected to with the code upon signin. this can be a list of urls.
        logoutUrls: ["https://dd7ec0n7fuvn7.cloudfront.net/"], // This is what user is allowed to be redirected to after signout. this can be a list of urls.
      },
    });

    const domain = userPool.addDomain("Todosdomain", {
      cognitoDomain: {
        domainPrefix: "muhib-todos", // SET YOUR OWN Domain PREFIX HERE
      },
    });

    new cdk.CfnOutput(this, "aws_user_pools_web_client_id", {
      value: userPoolClient.userPoolClientId,
    });
    new cdk.CfnOutput(this, "aws_project_region", {
      value: this.region,
    });
    new cdk.CfnOutput(this, "aws_user_pools_id", {
      value: userPool.userPoolId,
    });

    new cdk.CfnOutput(this, "domain", {
      value: domain.domainName,
    });


    // Appsync API for todo app schema
    const Todoapi = new appsync.GraphqlApi(this, "ApiForTodo", {
      name: "appsyncEventbridgeAPITodo",
      schema: appsync.Schema.fromAsset("utils/schema.gql"),
      authorizationConfig: {
        defaultAuthorization: {
          authorizationType: appsync.AuthorizationType.API_KEY,
        },
      },
      xrayEnabled: true,
    });

    // Prints out the AppSync GraphQL endpoint to the terminal
    new cdk.CfnOutput(this, "todoURL", {
      value: Todoapi.graphqlUrl
    });

    // Prints out the AppSync GraphQL API key to the terminal
    new cdk.CfnOutput(this, "TodoApiKey", {
      value: Todoapi.apiKey || ''
    });

    // Prints out the AppSync Api to the terminal
    new cdk.CfnOutput(this, "TodoAPI-ID", {
      value: Todoapi.apiId || ''
    });

    // Create new DynamoDB Table for Todos
    const TodoAppTable = new dynamoDB.Table(this, 'TodAppTable', {
      tableName: "TodoTable",
      partitionKey: {
        name: 'id',
        type: dynamoDB.AttributeType.STRING,
      },
    });

    // DynamoDB as a Datasource for the Graphql API.
    const TodoAppDS = Todoapi.addDynamoDbDataSource('TodoAppDataSource', TodoAppTable);

    ////////////////////////////// Creating Lambda handler //////////////////////
    const dynamoHandlerLambda = new lambda.Function(this, 'Dynamo_Handler', {
      code: lambda.Code.fromAsset('lambda'),
      runtime: lambda.Runtime.NODEJS_12_X,
      handler: 'dynamoHandler.handler',
      environment: {
        DYNAMO_TABLE_NAME: TodoAppTable.tableName,
      },
    });
    // Giving Table access to dynamoHandlerLambda
    TodoAppTable.grantReadWriteData(dynamoHandlerLambda);

    TodoAppDS.createResolver({
      typeName: "Query",
      fieldName: 'getTodos',
      requestMappingTemplate: appsync.MappingTemplate.dynamoDbScanTable(),
      responseMappingTemplate: appsync.MappingTemplate.dynamoDbResultList(),
    });


    // HTTP as Datasource for the Graphql API
    const httpEventTriggerDS = Todoapi.addHttpDataSource(
      "eventTriggerDS",
      "https://events." + this.region + ".amazonaws.com/", // This is the ENDPOINT for eventbridge.
      {
        name: "httpDsWithEventBridge",
        description: "From Appsync to Eventbridge",
        authorizationConfig: {
          signingRegion: this.region,
          signingServiceName: "events",
        },
      }
    );


    /* Mutation */
    const mutations = ["addTodo", "deleteTodo",]
    mutations.forEach((mut) => {
      let details = `\\\"todoId\\\": \\\"$ctx.args.todoId\\\"`;
      if (mut === 'addTodo') {
        details = `\\\"title\\\":\\\"$ctx.args.todo.title\\\" , \\\"user\\\":\\\"$ctx.args.todo.user\\\"`
      } else if (mut === "deleteTodo") {
        details = `\\\"todoId\\\":\\\"$ctx.args.todoId\\\"`
      }
      httpEventTriggerDS.createResolver({
        typeName: "Mutation",
        fieldName: mut,
        requestMappingTemplate: appsync.MappingTemplate.fromString(requestTemplate(details, mut)),
        responseMappingTemplate: appsync.MappingTemplate.fromString(responseTemplate()),
      });
    });

    events.EventBus.grantPutEvents(httpEventTriggerDS);

    ////////// Creating rule to invoke step function on event ///////////////////////
    new events.Rule(this, "eventConsumerRule", {
      eventPattern: {
        source: [EVENT_SOURCE],
      },
      targets: [new eventsTargets.LambdaFunction(dynamoHandlerLambda)]
    });


    //here I define s3 bucket 
    const todosBucket = new s3.Bucket(this, "todosBucket", {
      versioned: true,
    });

    todosBucket.grantPublicAccess(); // website visible to all.

    // create a CDN to deploy your website
    const distribution = new cloudfront.Distribution(this, "TodosDistribution", {
      defaultBehavior: {
        origin: new origins.S3Origin(todosBucket),
      },
      defaultRootObject: "index.html",
    });


    // Prints out the web endpoint to the terminal
    new cdk.CfnOutput(this, "DistributionDomainName", {
      value: distribution.domainName,
    });


    // housekeeping for uploading the data in bucket 
    new s3deploy.BucketDeployment(this, "DeployTodoApp", {
      sources: [s3deploy.Source.asset("../frontend/public")],
      destinationBucket: todosBucket,
      distribution,
      distributionPaths: ["/*"],
    });
  }
}<file_sep>import { EventBridgeEvent, Context } from 'aws-lambda';
export declare const handler: (event: EventBridgeEvent<string, any>, context: Context) => Promise<void>;
<file_sep>import React, { useState, useRef, useEffect, useContext } from "react";
import { Router } from "@reach/router";
import { addTodo } from "../graphql/mutations";
import { getTodos } from "../graphql/queries";
import { deleteTodo } from "../graphql/mutations";
import { API } from "aws-amplify";
import { IdentityContext } from "../../Identity-Context";
import Navbar from "../components/Navbar";
import { Link } from 'gatsby';
import { Button, Heading, Input, Label, NavLink, Text } from "theme-ui";

const Dash = () => {
    const { user } = useContext(IdentityContext);
    const [loading, setLoading] = useState(true)
    const [todoData, setTodoData] = useState(null)
    const todoTitleRef = useRef("")

    const addTodoMutation = async () => {
        try {
            const todo = {
                title: todoTitleRef.current.value,
                user: user.username
            }
            await API.graphql({
                query: addTodo,
                variables: {
                    todo: todo,
                },
            })
            todoTitleRef.current.value = ""
            fetchTodos();
        } catch (e) {
            console.log(e)
        }
    }

    const fetchTodos = async () => {
        try {
            const data = await API.graphql({
                query: getTodos,
            })
            setTodoData(data);
            console.log(data);
            setLoading(false)
        } catch (e) {
            console.log(e)
        }
    }
    useEffect(() => {
        fetchTodos()
    }, [])
    return (
        <div>
            {loading ? (
                <Heading as="h3" sx={{ textAlign: "center" }}>Loading...</Heading>
            ) : (
                    <div>
                        <Navbar /><br /><br />
                        <Heading as="h3" sx={{ textAlign: "center" }}>Make Schedule Easy</Heading>
                        <Label>
                            <Input ref={todoTitleRef} />
                        </Label><br />
                        <Button sx={{ color: "black", textAlign: "center" }} onClick={() => addTodoMutation()}>Create Todo</Button><br /><br />
                        <Heading as="h2" sx={{ textAlign: "center" }}>Your Todo List</Heading>
                        {todoData.data &&
                            todoData.data.getTodos.filter((todo) => todo.user === user.username).map((item, ind) => (
                            // todoData.data.getTodos.map((item, ind) => (
                                <div style={{ marginLeft: "1rem", marginTop: "2rem" }} key={ind}>
                                    <Text sx={{ fontSize: 4, fontWeight: 'italic', margin: '5px'}}>{item.title}</Text>
                                    <div>
                                        <Button
                                            sx={{ color: "black", textAlign: "center" }}
                                            onClick={async e => {
                                                e.preventDefault();
                                                await API.graphql({
                                                    query: deleteTodo,
                                                    variables: { todoId: item.id },
                                                })
                                                fetchTodos();
                                            }}
                                        >Delete Todo</Button>
                                    </div>
                                </div>
                            ))}
                    </div>
                )}
        </div>
    );
};

const App = () => {
    const { user } = useContext(IdentityContext);
    return (
        <>
            <Router>{user && <Dash path="/app" />}</Router>
            {!user && <NavLink as={Link} to="/" p={2}>Home</NavLink>}
        </>)
};

export default App;<file_sep>export declare const EVENT_SOURCE = "todo-app-events";
export declare const requestTemplate: (detail: string, detailType: string) => string;
export declare const responseTemplate: () => string;
<file_sep>import React, { useContext } from "react";
import { Button, Container, Flex, Heading } from "theme-ui";
import { IdentityContext } from "../../Identity-Context";
import Navbar from "../components/Navbar";
import { Link } from "gatsby";
import { Auth } from "aws-amplify";

const Index = () => {
  const { user } = useContext(IdentityContext);
  return (
    <Container>
      <Navbar />
      <Flex sx={{ flexDirection: "column", padding: 3, textAlign: "center" }}>
        <Heading as="h1">Todo App</Heading>
        {!user && (
          <Button
            sx={{ marginTop: 2, color: 'black', fontFamily: 'monospace', cursor: 'pointer' }}
            onClick={() => {
              Auth.federatedSignIn({ provider: "Google"})
            }}
          >
            Login
          </Button>
        )}
        {user && (
            <Button sx={{ marginTop: 2, color: 'black', cursor: 'pointer' }}>
              <Link to='app/'>Create Todos</Link>
            </Button>
        )}
      </Flex>
    </Container>
  );
};

export default Index;