<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Christopher Coffee</title>
    <description>The latest articles on DEV Community by Christopher Coffee (@cmcoffeedev).</description>
    <link>https://dev.to/cmcoffeedev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F459880%2F83e9e4df-9253-45f6-a0b4-e7880b98d935.jpeg</url>
      <title>DEV Community: Christopher Coffee</title>
      <link>https://dev.to/cmcoffeedev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cmcoffeedev"/>
    <language>en</language>
    <item>
      <title>FlutterFlow Stepper Form with Firebase Firestore</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Mon, 02 Oct 2023 12:00:00 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/flutterflow-stepper-form-with-firebase-firestore-418</link>
      <guid>https://dev.to/cmcoffeedev/flutterflow-stepper-form-with-firebase-firestore-418</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A7J7hOMp3wcsD3U18f5fYxQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A7J7hOMp3wcsD3U18f5fYxQ.jpeg" alt="Photo by [Tony Pepe](https://unsplash.com/@tonypepe?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/flutter?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;I will show you how to create a custom widget in FlutterFlow to show a Stepper widget with form fields. We will submit the data to Firestore. This code is also reusable in non FlutterFlow generated apps.&lt;/p&gt;

&lt;p&gt;You may copy and paste the code, but I want to walk through the thought process of how I would implement this for educational purposes. We will create an app saves the user’s grocery list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A52vtb9Mfz1sSXJoOUHq7fQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A52vtb9Mfz1sSXJoOUHq7fQ.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Form Field
&lt;/h3&gt;

&lt;p&gt;First, we will use the FlutterFlow UI builder to create a TextFormField. You may also write the code yourself. In the blank home page of your project. Drag and drop a form field and style it how you want. I will also add the hint text.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6360%2F1%2AnVtmoVve99PJN83OJexnsA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6360%2F1%2AnVtmoVve99PJN83OJexnsA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Firestore Collection
&lt;/h3&gt;

&lt;p&gt;Now let’s create the Firestore Collection in FlutterFlow. I am assuming you have already followed FlutterFlow documentation on connecting your firebase project.&lt;/p&gt;

&lt;p&gt;Click on the Firestore tab, then click &lt;strong&gt;Create Collection&lt;/strong&gt;. It will ask if you want to use a template, and you can choose the product template. I have deleted some fields.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4448%2F1%2AeHSwaDdwabYPe6av4fyaPg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4448%2F1%2AeHSwaDdwabYPe6av4fyaPg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Custom Widget
&lt;/h3&gt;

&lt;p&gt;Now let’s create the custom form widget. Click the &lt;strong&gt;Custom Function&lt;/strong&gt; tab on the left, then click the &lt;strong&gt;Custom Widget&lt;/strong&gt; tab within that screen. Click the purple &lt;strong&gt;Create&lt;/strong&gt; button. You should now see this screen. Name the widget and click &lt;strong&gt;View Boilerplate Code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AD0tI0JtTjx9MciPCuaWhqA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AD0tI0JtTjx9MciPCuaWhqA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will show another popup. Click &lt;strong&gt;Copy to Editor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3260%2F1%2A5eeVccMs9gektafa1JfYgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3260%2F1%2A5eeVccMs9gektafa1JfYgg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Go back to the TextField you created. Right-click on the TextField from the &lt;strong&gt;Widget Tree **and click **Copy Widget Code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2096%2F1%2AgKopiuBmiQMl3kYaP8Uf1A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2096%2F1%2AgKopiuBmiQMl3kYaP8Uf1A.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go back to the custom widget you created and click the edit button (pencil icon). Above the build function, we will create another function that returns our form.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; @override
 Widget build(BuildContext context) {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Create a function that takes a textController and hint text. Type return, then copy and paste the code you copied earlier. The decoration code may be different depending on how you styled your code.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Widget getTextFormWidget(
      TextEditingController textController, String customHintText) {
    return TextFormField(
      controller: textController,
      autofocus: true,
      obscureText: false,
      decoration: InputDecoration(
        hintText: customHintText,
        hintStyle: FlutterFlowTheme.of(context).bodyText2,
        enabledBorder: UnderlineInputBorder(
          borderSide: BorderSide(
            color: Color(0x00000000),
            width: 1,
          ),
          borderRadius: const BorderRadius.only(
            topLeft: Radius.circular(4.0),
            topRight: Radius.circular(4.0),
          ),
        ),
        focusedBorder: UnderlineInputBorder(
          borderSide: BorderSide(
            color: Color(0x00000000),
            width: 1,
          ),
          borderRadius: const BorderRadius.only(
            topLeft: Radius.circular(4.0),
            topRight: Radius.circular(4.0),
          ),
        ),
        errorBorder: UnderlineInputBorder(
          borderSide: BorderSide(
            color: Color(0x00000000),
            width: 1,
          ),
          borderRadius: const BorderRadius.only(
            topLeft: Radius.circular(4.0),
            topRight: Radius.circular(4.0),
          ),
        ),
        focusedErrorBorder: UnderlineInputBorder(
          borderSide: BorderSide(
            color: Color(0x00000000),
            width: 1,
          ),
          borderRadius: const BorderRadius.only(
            topLeft: Radius.circular(4.0),
            topRight: Radius.circular(4.0),
          ),
        ),
      ),
      style: FlutterFlowTheme.of(context).bodyText1,
    );
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Above this function copy these three lines of code. We will use the TextControllers to get the text from the TextField before submitting the form.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final nameController = TextEditingController();
final priceController = TextEditingController();
final quantityController = TextEditingController();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Now let’s create a Stepper Widget. Let’s get the code from Flutter’s official Stepper Widget documentation.&lt;br&gt;
&lt;a href="https://api.flutter.dev/flutter/material/Stepper-class.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Stepper class - material library - Dart API&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Replace your build method with the code from the documentation. At this point, you may want to save the code, then click edit again.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int _index = 0;

@override
  Widget build(BuildContext context) {
    return Stepper(
      currentStep: _index,
      onStepCancel: () {
        if (_index &amp;gt; 0) {
          setState(() {
            _index -= 1;
          });
        }
      },
      onStepContinue: () {
        if (_index &amp;lt;= 0) {
          setState(() {
            _index += 1;
          });
        }
      },
      onStepTapped: (int index) {
        setState(() {
          _index = index;
        });
      },
      steps: &amp;lt;Step&amp;gt;[
        Step(
          title: const Text('Step 1 title'),
          content: Container(
              alignment: Alignment.centerLeft,
              child: const Text('Content for Step 1')),
        ),
        const Step(
          title: Text('Step 2 title'),
          content: Text('Content for Step 2'),
        ),
      ],
    );
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;We will replace the steps with our custom text fields.&lt;/p&gt;

&lt;p&gt;We also copied the index variable, so that we may change Steps.&lt;/p&gt;

&lt;p&gt;Replace the steps with the following code. In the first Step widget, we will have only one text field, which is the name field. Notice we are passing the nameController and the hint text.&lt;/p&gt;

&lt;p&gt;In the second Step widget we have a column that holds the price text field, quantity text field and the save button. The save button calls a function called submit form, which we haven’t defined yet. We could also wrap the Stepper widget with a column and add the button at the bottom. For simplicity, we will keep it like this.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step(
   title: const Text('Product Name'),
   content: getTextFormWidget(nameController, 'Enter The Product Name'),
),
Step(
    title: const Text('Product Name'),
    content: Column(
        children: [
            getTextFormWidget(priceController, 'Enter The Product Price'),
            getTextFormWidget(quantityController, 'Enter The Product Quantity'),
            ElevatedButton(
              onPressed: submitForm,
               child: const Text('Save'),
            ),
        ],
     ),
),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Save to Firebase
&lt;/h3&gt;

&lt;p&gt;Above the build function, create another function named submitForm.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; void submitForm() async {

 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;In FlutterFlow’s UI builder, when creating an action to save the data, it has methods it generates that are exposed through backend.dart. It would generate code like this to save data. Although this will work if you download the code, it will not compile on the FlutterFlow platform.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final groceryRequestCreateData = 
    createGroceryItemRecordData( 
        name: nameController.text,
        price: double.parse(priceController.text),
        quantity: int.parse(quantityController.text),
    );
    await GroceryItemRecord.collection
    .doc()
    .set(emergencyRequestCreateData);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;So let’s use the FlutterFire documentation to save this data to Firestore.&lt;br&gt;
&lt;a href="https://firebase.flutter.dev/docs/firestore/usage/" rel="noopener noreferrer"&gt;&lt;strong&gt;Cloud Firestore | FlutterFire&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following code shows the solution to submit the code to firebase.&lt;/p&gt;

&lt;p&gt;First, we will put the reference to the GroceryItem collection. We are creating a random id using the grocery collection reference.&lt;br&gt;
&lt;a href="https://stackoverflow.com/a/67333873" rel="noopener noreferrer"&gt;&lt;strong&gt;Can i generate Doc id from flutter to firebase without the method add?&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we are using setting the data using the textControllers. We have to parse price and quantity controllers to their respective data types.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CollectionReference groceryItemRef =
      FirebaseFirestore.instance.collection('GroceryItem');

 void submitForm() async {
    try {
      var randomId = groceryItemRef.doc().id;
      await groceryItemRef.doc(randomId).set({
        'name': nameController.text,
        'price': double.parse(priceController.text),
        'quantity': int.parse(quantityController.text)
      });
    } catch (e) {
      print('Error saving grocery item: $e');
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Format and Save your code. Click edit again, then click Compile and Preview. You should see a preview of your form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4328%2F1%2AhkalAEgx0pQUqI0wUCMvKQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4328%2F1%2AhkalAEgx0pQUqI0wUCMvKQ.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Test your custom StepperForm widget
&lt;/h3&gt;

&lt;p&gt;Now let’s go back to the UI builder in FlutterFlow. Remove the text field you created and replace it with the custom StepperForm widget.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Awkajet39IATaNPC8GIuwDw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Awkajet39IATaNPC8GIuwDw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now use Test Mode to test it out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Az8MsY55hArVROxi1UuRC1w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Az8MsY55hArVROxi1UuRC1w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you click the &lt;strong&gt;Save&lt;/strong&gt; button, go to Firestore in the Firebase console. You should see the data from your form. You could use a dialog to show the success of the submission.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5112%2F1%2Ad-x13Un6U8TR3GsfkOQPBQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5112%2F1%2Ad-x13Un6U8TR3GsfkOQPBQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the complete code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://api.flutter.dev/flutter/material/Stepper-class.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Stepper class - material library - Dart API&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://firebase.flutter.dev/docs/firestore/usage/" rel="noopener noreferrer"&gt;&lt;strong&gt;Cloud Firestore | FlutterFire&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://api.flutter.dev/flutter/material/TextFormField-class.html" rel="noopener noreferrer"&gt;&lt;strong&gt;TextFormField class - material library - Dart API&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/67333829/can-i-generate-doc-id-from-flutter-to-firebase-without-the-method-add/67333873#67333873" rel="noopener noreferrer"&gt;&lt;strong&gt;Can i generate Doc id from flutter to firebase without the method add?&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
      <category>android</category>
    </item>
    <item>
      <title>AWS Fundamentals: IAM, GitHub, and AWS CLI</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Sun, 01 Oct 2023 12:00:00 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/aws-fundamentals-iam-github-and-aws-cli-1776</link>
      <guid>https://dev.to/cmcoffeedev/aws-fundamentals-iam-github-and-aws-cli-1776</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;In this article, we will create an Admin user in AWS. We will also install the AWS CLI to create AWS Billing Alarms and Budgets.&lt;/p&gt;

&lt;p&gt;You can do many things with the AWS CLI, but I want to start with something to get a simple understanding of it.&lt;/p&gt;

&lt;p&gt;We will use gitpod to install the AWS CLI to make it accessible for everyone following along.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a new Admin user
&lt;/h3&gt;

&lt;p&gt;Create a new user in the IAM Users Console by searching IAM or going to &lt;a href="https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/users" rel="noopener noreferrer"&gt;https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/users&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4216%2F1%2A_9fVr6pXQdjureIjrpNySw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4216%2F1%2A_9fVr6pXQdjureIjrpNySw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Add users&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5812%2F1%2AAd8Hl1mgJIsHvGh8jrUpTA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5812%2F1%2AAd8Hl1mgJIsHvGh8jrUpTA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In step 1, Enable &lt;strong&gt;AWS Management Console&lt;/strong&gt; access, choose I &lt;strong&gt;want to create an IAM user&lt;/strong&gt;, choose your password preferences, then click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5412%2F1%2AoAuZRzEAHn-OjWId46PN3Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5412%2F1%2AoAuZRzEAHn-OjWId46PN3Q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 2 is used to set the user’s permissions. We want to add the user to an Administrator group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aoh4y1AcVC7r34-bUCQwTNQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aoh4y1AcVC7r34-bUCQwTNQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don’t have a group, create one by clicking &lt;strong&gt;Create group&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AYQ575lLhg1xewGOPCWYdnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AYQ575lLhg1xewGOPCWYdnw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give the group a name, such as Admin and check &lt;strong&gt;AdministratorAccess&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3192%2F1%2AtKB1kyp-IIeF2C8lHXs_5A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3192%2F1%2AtKB1kyp-IIeF2C8lHXs_5A.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Create user group&lt;/strong&gt; at the bottom.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2API--tduu9RwNXjSuY7metw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2API--tduu9RwNXjSuY7metw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check the Admin group you want to add the user to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AmtZeIARckX6qA5EXTc4Qog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AmtZeIARckX6qA5EXTc4Qog.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click Next, then &lt;strong&gt;Create User&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AquTjncScuzycivYhXi325w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AquTjncScuzycivYhXi325w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create IAM User Access Key
&lt;/h3&gt;

&lt;p&gt;Click the user name of the IAM user, then click the &lt;strong&gt;Security Credentials&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AAVpn-_FJ0pcpsb-D-pGskQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AAVpn-_FJ0pcpsb-D-pGskQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click &lt;strong&gt;Create Access Key&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AvA439yP5ZvngVE0N4WOg5Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AvA439yP5ZvngVE0N4WOg5Q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Command Line Interface (CLI)&lt;/strong&gt; then click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4424%2F1%2AoccEv0dQJiG__3Xm-Exh4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4424%2F1%2AoccEv0dQJiG__3Xm-Exh4w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Create access key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4436%2F1%2A5Wa8aMHVjXw2wfPR5fxTSg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4436%2F1%2A5Wa8aMHVjXw2wfPR5fxTSg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will give you an access key and a secret access key. Keep these in a safe place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a GitHub Account
&lt;/h3&gt;

&lt;p&gt;We will use GitHub to store our code. Visit GitHub to create a new account.&lt;br&gt;
&lt;a href="https://github.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub: Let's build from here&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the top right, click the plus icon. Then click &lt;strong&gt;New Repository&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ACgLiq-HW5-ux9aCqtjUdvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ACgLiq-HW5-ux9aCqtjUdvw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give the repository a name and set the visibility&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3056%2F1%2Ak8iEYc8nOvRHNep89EE16Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3056%2F1%2Ak8iEYc8nOvRHNep89EE16Q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Create Repository&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Gitpod account
&lt;/h3&gt;

&lt;p&gt;Gitpod gives you an online dev environment. You will run our code here. You can also follow along on your personal computer as well just skip this part.&lt;/p&gt;

&lt;p&gt;Sign up for a free Gitpod account here:&lt;br&gt;
&lt;a href="https://www.gitpod.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;Gitpod: Always ready to code.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It may ask you what editor you want to use if you haven’t chosen a default. We will be using Visual Studio Code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Download the chrome extension for Gitpod.&lt;br&gt;
&lt;a href="https://chrome.google.com/webstore/detail/gitpod-always-ready-to-co/dodmmooeoklaejobgleioelladacbeki" rel="noopener noreferrer"&gt;&lt;strong&gt;Gitpod - Always ready to code&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go back to your Github repository and reload the page. You should now see a green Gitpod button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A1JYQmQTGc111QVlVGsUYKw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A1JYQmQTGc111QVlVGsUYKw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click **Gitpod **and you should see the following screen&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2528%2F1%2AlP2J_e4BC4kR15gEWWPe3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2528%2F1%2AlP2J_e4BC4kR15gEWWPe3g.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Continue with Github&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It may ask you what editor you want to use if you haven’t chosen a default. We will be using Visual Studio Code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You should now have an environment with VS Code similar to the following.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6448%2F1%2A_QqS1CgkNIkJh4pv427TPg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6448%2F1%2A_QqS1CgkNIkJh4pv427TPg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the AWS CLI
&lt;/h3&gt;

&lt;p&gt;We will use the Linux instructions for installing the CLI, but you may refer to your operating system’s instructions in the AWS CLI documentation.&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Installing or updating the latest version of the AWS CLI&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Download the AWS CLI&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Unzip the CLI tool&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;unzip awscliv2.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Install the AWS CLI.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ./aws/install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Check the AWS version installed&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2380%2F1%2AvaLC5leRpy0xMhbUhYCrqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2380%2F1%2AvaLC5leRpy0xMhbUhYCrqg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Set AWS environment variables
&lt;/h3&gt;

&lt;p&gt;Now we can use the keys we created earlier and set them to environment variables so that we may work with the AWS CLI.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gp env AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
gp env AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
gp env AWS_DEFAULT_REGION=us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can verify that env are saved within gitpod by going here: &lt;a href="https://gitpod.io/user/variables" rel="noopener noreferrer"&gt;https://gitpod.io/user/variables&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check that we are getting the expected user with the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws sts get-caller-identity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can also save our AWS account id to the gitpod environment variables&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gp env AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Create a Billing Alarm (via the CLI)
&lt;/h3&gt;

&lt;p&gt;Refer to the AWS CLI docs to create a SNS Topic by running this command in the terminal&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws sns create-topic --name example-billing-alarm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/reference/sns/create-topic.html#examples" rel="noopener noreferrer"&gt;&lt;strong&gt;create-topic - AWS CLI 1.27.79 Command Reference&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will give you a topic arn to use in the next command&lt;/p&gt;

&lt;p&gt;Refer to the AWS CLI docs to subscribe to a topic using the topic arn from the previous command’s output.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws sns subscribe \
    --topic-arn arn:aws:sns:us-east-2:123456789012:example-billing-alarm \
    --protocol email \
    --notification-endpoint my-email@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/sns/subscribe.html" rel="noopener noreferrer"&gt;&lt;strong&gt;subscribe - AWS CLI 2.10.3 Command Reference&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Verify the alarm was created in the AWS Console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://us-east-1.console.aws.amazon.com/cloudwatch/home?region=us-east-1#alarmsV2" rel="noopener noreferrer"&gt;https://us-east-1.console.aws.amazon.com/cloudwatch/home?region=us-east-1#alarmsV2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It may take a few minutes before the alarm is created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create an AWS budget (via the CLI)
&lt;/h2&gt;

&lt;p&gt;Create folders aws and json, and go to the json folder using the following command in the terminal&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p aws/json &amp;amp;&amp;amp; cd aws/json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Go to the AWS CLI create budget documentation: &lt;a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/budgets/create-budget.html#examples" rel="noopener noreferrer"&gt;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/budgets/create-budget.html#examples&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the budget.json and notifications-with-subscribers.json examples into the json folder.&lt;/p&gt;

&lt;p&gt;To create a new file you may click the &lt;strong&gt;New File…&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AiWePQXF-HQcQjpF56xXpJQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AiWePQXF-HQcQjpF56xXpJQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run this command in your terminal to create the budget&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws budgets create-budget \
    --account-id $AWS_ACCOUNT_ID \
    --budget file://aws/json/budget.json \
    --notifications-with-subscribers file://aws/json/notifications-with-subscribers.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Verify your budget was created in the AWS console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://us-east-1.console.aws.amazon.com/billing/home#/budgets/overview" rel="noopener noreferrer"&gt;https://us-east-1.console.aws.amazon.com/billing/home#/budgets/overview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations on creating a new IAM user, Github, and Gitpod account. You are now familiar with the AWS CLI, which we will use more in the future.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Leetcode: Single Number (Kotlin)</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Sat, 30 Sep 2023 10:00:00 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/leetcode-single-number-kotlin-17nc</link>
      <guid>https://dev.to/cmcoffeedev/leetcode-single-number-kotlin-17nc</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2560%2F1%2ASMPQonqL-eilcL5HfheW2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2560%2F1%2ASMPQonqL-eilcL5HfheW2g.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Single Number&lt;/em&gt;&lt;/strong&gt; is an easy question on Leetcode. I will discuss the problem and my solution below.&lt;br&gt;
&lt;a href="https://leetcode.com/problems/single-number/" rel="noopener noreferrer"&gt;&lt;strong&gt;Single Number - LeetCode&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Problem Statement
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2928%2F1%2APQXYLLo8vFORAxJn0WXv4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2928%2F1%2APQXYLLo8vFORAxJn0WXv4g.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A8TwVeY3c8KaxZLj0cUYH-A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A8TwVeY3c8KaxZLj0cUYH-A.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Constraints
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2664%2F1%2Aq5eVtGRsxcJ8s6G00REhcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2664%2F1%2Aq5eVtGRsxcJ8s6G00REhcg.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Brainstorm
&lt;/h3&gt;

&lt;p&gt;The solution I thought of is pretty straightforward.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;They give us an array of integers, so we can use a map that will store each number as the key and the count of that number as the value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We iterate through the array to set each number’s count in the map.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We will then iterate through the array again, but this time we will check each number’s count in the map and return the number with the count of one&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;They guarantee a number with a count of one is in the given array, so you could technically return any number at the end because it should never get to that point. I use Int.MIN_VALUE.&lt;/p&gt;
&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


</description>
      <category>leetcode</category>
      <category>kotlin</category>
      <category>android</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Monitor Android’s filesystem with fsmon to detect insecure storage</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Fri, 29 Sep 2023 13:00:00 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/monitor-androids-filesystem-with-fsmon-to-detect-insecure-storage-37cn</link>
      <guid>https://dev.to/cmcoffeedev/monitor-androids-filesystem-with-fsmon-to-detect-insecure-storage-37cn</guid>
      <description>&lt;p&gt;I’m diving deeper into security and wanted to document my process along the way. First I am going over the process of monitoring an Android device’s filesystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Download Android Studio or Android command line tools
&lt;/h3&gt;

&lt;p&gt;You have two options to get the Android developer tools.&lt;/p&gt;

&lt;p&gt;If you want to just use Android command line tools, you will also need to install Java.&lt;/p&gt;

&lt;p&gt;Alternatively, you can also install Android Studio, which will install everything for you.&lt;/p&gt;

&lt;p&gt;Download both below&lt;br&gt;
&lt;a href="https://developer.android.com/studio"&gt;&lt;strong&gt;Download Android Studio &amp;amp; App Tools - Android Developers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add platform tools to your PATH (optional)
&lt;/h3&gt;

&lt;p&gt;You will also need to add the Android platform-tools to your PATH&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export PATH=$PATH:/Users/&amp;lt;computerName&amp;gt;/Library/Android/sdk/platform-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The main command we will use is adb. Type adb in your terminal and it should give you the list of commands your path is configured correctly.&lt;/p&gt;

&lt;p&gt;You can also go directly to the platform-tools directory and run the command there as a temporary solution. You can also run the following command each time&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Users/&amp;lt;computerName&amp;gt;/Library/Android/sdk/platform-tools/adb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can also add this to your shell’s configuration so that it does this automatically. By default, Mac uses zsh, so you can create a file named .zshrc and add the command to the file. Then close and open a new terminal or run the following command if you choose to use the same terminal.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source .zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://unix.stackexchange.com/a/71258"&gt;&lt;strong&gt;What should/shouldn't go in .zshenv, .zshrc, .zlogin, .zprofile, .zlogout?&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up a virtual rooted Android Device
&lt;/h3&gt;

&lt;p&gt;You need a rooted device, luckily emulators have root access by default, so there is no need to root your personal device.&lt;/p&gt;

&lt;p&gt;If you installed Android Studio, you can use the AVD manager to create an emulator.&lt;br&gt;
&lt;a href="https://developer.android.com/studio/run/managing-avds"&gt;&lt;strong&gt;Create and manage virtual devices | Android Studio | Android Developers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you downloaded the command-line tools you can create an emulator by following the avdmanager Android docs&lt;br&gt;
&lt;a href="https://developer.android.com/tools/avdmanager"&gt;&lt;strong&gt;avdmanager | Android Studio | Android Developers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another popular alternative is Genymotion.&lt;br&gt;
&lt;a href="https://www.genymotion.com/"&gt;&lt;strong&gt;Android Emulator on the Cloud and cross-platform - Genymotion&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure to note the architecture used. Android Studio should show you when you’re creating the device, of course you specify it when using the avdmanager command, but I’m not currently sure on Genymotion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Download fsmon
&lt;/h3&gt;

&lt;p&gt;Let’s start by downloading fsmon. There are specific versions for Android. Download the one that matches your emulator architecture&lt;br&gt;
&lt;a href="https://github.com/nowsecure/fsmon/releases"&gt;&lt;strong&gt;Releases · nowsecure/fsmon&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Download the Insecure Shop apk
&lt;/h3&gt;

&lt;p&gt;I plan to use this app quite often to demonstrate different vulnerabilities on Android. You can download the APK here:&lt;br&gt;
&lt;a href="https://github.com/hax0rgb/InsecureShop"&gt;&lt;strong&gt;GitHub - hax0rgb/InsecureShop: An Intentionally designed Vulnerable Android Application built in…&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using ADB
&lt;/h3&gt;

&lt;p&gt;We are only going to use a few adb commands in this article.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install the Insecure shop apk with the following command&lt;/p&gt;

&lt;p&gt;adb install InsecureShop.apk&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get root Access&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;adb root&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push the fsmon to our Android device&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;adb push fsmon-and-x86_64 /data/local/tmp&lt;br&gt;
&lt;a href="https://forum.xda-developers.com/t/files-in-data-local-tmp.632396/#:~:text=Files%20in%20%2Fdata%2Flocal%2Ftmp%20are%20temporary%20files%20that,files%20inside%20it%20keep%20existing"&gt;&lt;strong&gt;Files in /data/local/tmp!?&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get shell access to the Android device&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;adb shell&lt;/p&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Data for Android apps are stored at the following location: &lt;strong&gt;/data/data/&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We want to monitor &lt;strong&gt;/data/data/com.insecureshop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lets go to &lt;strong&gt;/data/local/tmp&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /data/local/tmp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now let’s monitor the directory&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./fsmon-and-x86_64 /data/data/com.insecureshop/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I haven’t opened the app yet, so I see the following&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xmDO9OMQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2AwWdPKJOUO99z3MigwKFOYA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xmDO9OMQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2AwWdPKJOUO99z3MigwKFOYA.png" alt="" width="800" height="76"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s open the app and you will see that it creates the shared preferences directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--psFhlhIj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2752/1%2Awm7bIM5j4VxWgElworgzdA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--psFhlhIj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2752/1%2Awm7bIM5j4VxWgElworgzdA.png" alt="" width="800" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read more about shared preferences&lt;br&gt;
&lt;a href="https://developer.android.com/training/data-storage/shared-preferences"&gt;&lt;strong&gt;Save simple data with SharedPreferences | Android Developers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Login with user name &lt;strong&gt;shopuser&lt;/strong&gt; and password &lt;strong&gt;!ns3csh0p&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You will see that it has modified a lot of data in the directory&lt;/p&gt;

&lt;p&gt;Open another terminal and gain shell access to the device again&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adb shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now let’s go to &lt;strong&gt;/data/data/com.insecureshop&lt;/strong&gt; and inspect the shared preferences file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat /data/data/com.insecureshop/shared_prefs/Prefs.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---ZlLicCW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2624/1%2AC5JnjMnygOhvMXSbAwt0sA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---ZlLicCW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2624/1%2AC5JnjMnygOhvMXSbAwt0sA.png" alt="" width="800" height="684"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that they are saving the password and user name to the file.&lt;/p&gt;

&lt;p&gt;Also, note that Google is recommending moving from shared prefs to data store. This file will also be available in the &lt;strong&gt;/data/data/&lt;/strong&gt; directory of the device.&lt;br&gt;
&lt;a href="https://developer.android.com/topic/libraries/architecture/datastore"&gt;&lt;strong&gt;App Architecture: Data Layer - DataStore - Android Developers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is best practice to never store sensitive info, even encrypted. Also refer to the **OWASP MASTG ( Mobile Application Security Testing Guide ) **for other best practices.&lt;br&gt;
&lt;a href="https://mas.owasp.org/MASTG/Android/0x05d-Testing-Data-Storage/"&gt;&lt;strong&gt;Android Data Storage - OWASP Mobile Application Security&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>androiddev</category>
      <category>cybersecurity</category>
      <category>linux</category>
      <category>terminal</category>
    </item>
    <item>
      <title>How To Set Up a Free Business Email Using Your Domain</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Thu, 28 Sep 2023 13:00:00 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/how-to-set-up-a-free-business-email-using-your-domain-1phi</link>
      <guid>https://dev.to/cmcoffeedev/how-to-set-up-a-free-business-email-using-your-domain-1phi</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F10368%2F1%2Ar-IS34bFFF6s1_2Q39qtgQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F10368%2F1%2Ar-IS34bFFF6s1_2Q39qtgQ.jpeg" alt="Photo by [Brett Jordan](https://unsplash.com/@brett_jordan?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/email?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setting up a professional email will help you stand out with your career and business. So instead of &lt;a href="mailto:chris@gmail.com"&gt;chris@gmail.com&lt;/a&gt;, I can use &lt;a href="mailto:chris@mycompanyname.com"&gt;chris@mycompanyname.com&lt;/a&gt;. I personally have a professional email that I use on my portfolio site and LinkedIn. This also helps keep my personal email separate and a little safer.&lt;/p&gt;

&lt;p&gt;I’ll show you how to create a professional email using Zoho. They are a well-known company with a suite of business applications. They give you 5 free emails starting out and you just pay $1 per extra email after that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6716%2F1%2AoONjZImujy-nJDpvuACr3A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6716%2F1%2AoONjZImujy-nJDpvuACr3A.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Your Domain With Zoho Mail
&lt;/h3&gt;

&lt;p&gt;Of course, if you don’t have a domain, you will need one to get started. I purchase my domains using &lt;a href="https://namecheap.com." rel="noopener noreferrer"&gt;https://namecheap.com&lt;/a&gt;. Zoho also allows you to purchase a domain after signing up.&lt;/p&gt;

&lt;p&gt;Click the link below to get started using Zoho:&lt;br&gt;
&lt;a href="https://mail.zoho.com/signup?type=org&amp;amp;plan=free" rel="noopener noreferrer"&gt;&lt;strong&gt;Email Sign up - Create a new email account with Zoho Mail&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will need to fill out this form and use your phone number or email to verify your account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4836%2F1%2ASeg_O7qwyGLbbTeVcZb2lQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4836%2F1%2ASeg_O7qwyGLbbTeVcZb2lQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, verify your account:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4472%2F1%2AL1kM6P2MMtJ1AOj5PqMm2w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4472%2F1%2AL1kM6P2MMtJ1AOj5PqMm2w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will get a welcome screen after verifying. You can click on the “Add Now” button if you already have a domain or “Buy Now” to buy one. I’ll assume you have bought one so click Add Now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6716%2F1%2Aoz7KBQjGuNMj9yHGx-pcMg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6716%2F1%2Aoz7KBQjGuNMj9yHGx-pcMg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6720%2F1%2ATw5ZCsUNphsaT_CKExuFdw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6720%2F1%2ATw5ZCsUNphsaT_CKExuFdw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the Proceed to domain verification button.&lt;/p&gt;

&lt;p&gt;Zoho can usually detect where your domain is hosted. I have my domain pointed to Digital Ocean, so it tries to help me out. Either way, the steps are the same across the board.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4888%2F1%2AWUmL4n4F0JFiAom13hVE3A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4888%2F1%2AWUmL4n4F0JFiAom13hVE3A.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can visit this link for specific instructions on where to find where to copy these values here:&lt;br&gt;
&lt;a href="https://www.zoho.com/mail/help/adminconsole/domain-verification.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Domain Verification - Email Hosting with Zoho&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ll walk through Digital Ocean, but it will be the same thing to copy and paste across the board.&lt;/p&gt;

&lt;p&gt;I’ve found on Digital Ocean where I need to create records. I chose the TXT tab to add a TXT record and added the value I copied. For the hostname using “@” (without quotes of course).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4732%2F1%2APmyqCGuYED9u0sesT1MWdg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4732%2F1%2APmyqCGuYED9u0sesT1MWdg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will click “Create Record” to create my TXT record. Now we need to go back to Zoho and click the “Verify TXT record” button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3540%2F1%2AO-igMUZ46T_77C_wtOJ8og.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3540%2F1%2AO-igMUZ46T_77C_wtOJ8og.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will now choose your administrator email. You can use your name, “info”, “support”, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3004%2F1%2AoEIAKawAXCgfDxVHOjxV-w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3004%2F1%2AoEIAKawAXCgfDxVHOjxV-w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the “Create” button. You can add more users if you would like. Let’s go to DNS Mapping by clicking next on the “Setup Users” and “Setup Groups” pages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6716%2F1%2APAmIi-fg66F2WWVEx9hR0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F6716%2F1%2APAmIi-fg66F2WWVEx9hR0w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see we need to add 3 MX records, and 2 TXT Records. Let’s work from the bottom up.&lt;/p&gt;

&lt;p&gt;We need to add a TXT record. First copy :&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zmail_domainkey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now set this as the host in Digital Ocean. You will set the value in the Value field.&lt;/p&gt;

&lt;p&gt;Now let’s copy:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 include:zoho.com ~all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is the last TXT Record to add. Set the host name as “@” (without quotes”).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4796%2F1%2ANnxQAGnT1yrkciI3vk1zXw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4796%2F1%2ANnxQAGnT1yrkciI3vk1zXw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s add all three MX records. In Digital Ocean we can click on the MX tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4868%2F1%2A-oxl1inLtjAiAmesee05nw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4868%2F1%2A-oxl1inLtjAiAmesee05nw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4876%2F1%2A_Y7isVIswUYmzJXLQj1A3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4876%2F1%2A_Y7isVIswUYmzJXLQj1A3g.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4820%2F1%2A7cmW1IYq9vDEbcMQ9KSs0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4820%2F1%2A7cmW1IYq9vDEbcMQ9KSs0w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can click “Verify All Records”. Depending on the TTL you set when adding the records, it may take a while to verify some of them. I usually keep the defaults when using Digital Ocean.&lt;/p&gt;

&lt;p&gt;You also do not have to wait to verify the records. The emails will work without staying on this page. They may also ask you to verify on the desktop when you log in, but not necessary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5478%2F1%2ALh-UXrO_1qU7-yvnskGDrg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5478%2F1%2ALh-UXrO_1qU7-yvnskGDrg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you do choose to wait for verification, you will get this message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3180%2F1%2AtR0nk8iAtqUA-KB99W6Paw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3180%2F1%2AtR0nk8iAtqUA-KB99W6Paw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you have set up your first professional email!&lt;/p&gt;

</description>
      <category>email</category>
      <category>smallbusiness</category>
      <category>domain</category>
    </item>
    <item>
      <title>Flutter Flow: Carousel Menu</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Wed, 27 Sep 2023 13:00:00 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/flutter-flow-carousel-menu-347k</link>
      <guid>https://dev.to/cmcoffeedev/flutter-flow-carousel-menu-347k</guid>
      <description>&lt;p&gt;I am going to discuss how to make a simple carousel menu in the Flutter Flow platform. I will provide the full source code as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Ab7SxlEwb59Vl-W3xWwIM9Q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Ab7SxlEwb59Vl-W3xWwIM9Q.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are going to use the following package to help us achieve this:&lt;br&gt;
&lt;a href="https://pub.dev/packages/carousel_slider/example" rel="noopener noreferrer"&gt;&lt;strong&gt;carousel_slider | Flutter Package&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Custom Widget
&lt;/h3&gt;

&lt;p&gt;First, let’s create our custom widget. Click the custom functions tab on the left-hand side of the flutter flow platform&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A-7iXjsG2aowws7RN7P0fPA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A-7iXjsG2aowws7RN7P0fPA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click &lt;strong&gt;Add &amp;gt; Widget&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AzLtUygMuHCWAAlAm5Qrg9A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AzLtUygMuHCWAAlAm5Qrg9A.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give your new widget a name such as &lt;strong&gt;CarouselMenu&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2780%2F1%2ANimfULu3zjy7bv5DTRrpYQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2780%2F1%2ANimfULu3zjy7bv5DTRrpYQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will need to pass JSON as a parameter to build our menu items. I will discuss this more later. Create a parameter called &lt;strong&gt;jsonMenuItems&lt;/strong&gt; of type JSON.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aw2wvDOiAoJjsHU2jtxHtkA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aw2wvDOiAoJjsHU2jtxHtkA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the green &lt;strong&gt;View Boilerplate Code&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aky7VGY_r89LW2oLYrO__eA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aky7VGY_r89LW2oLYrO__eA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It should show this screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3220%2F1%2AqUn6oRjk-QzokwpiL_jX0Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3220%2F1%2AqUn6oRjk-QzokwpiL_jX0Q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Copy to Editor&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now click &lt;strong&gt;Save&lt;/strong&gt; at the top right of the screen&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Adding Carousel Slider dependency&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Under the parameters add the carousel_slider dependency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AvgdBP-W9_4IHg16DINVUpA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AvgdBP-W9_4IHg16DINVUpA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt; again. Then click &lt;strong&gt;Compile.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Adding JSON menu items to local state
&lt;/h3&gt;

&lt;p&gt;For this example, we are going to store our menu items in Flutter Flow local state. You could also retrieve the JSON from an API.&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;Local State&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AUx372lwMxpr4N4jwEpuDtQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AUx372lwMxpr4N4jwEpuDtQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click &lt;strong&gt;Add State Variable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A61m6IskSGN7aNNkStoqO5Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A61m6IskSGN7aNNkStoqO5Q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a JSON field. You can name it the same as the parameter we created earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aom1D1e5sJea8lLHLGT8M5A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aom1D1e5sJea8lLHLGT8M5A.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Menu Item Example JSON
&lt;/h3&gt;

&lt;p&gt;You can use this example JSON array to populate your menu carousel. This is a JSON Array containing three JSON Objects. Each object is a menu item and contains a title, route, and imageUrl.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
If you look at the Flutter Flow source code you will see they use named routes to navigate in the app using the go router dependency. The route will be each screen’s Scaffold name. You will see this later.

&lt;p&gt;Copy this JSON as the default value for the state variable we just created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AOCgddpUnORlhCPL1U5KZZA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AOCgddpUnORlhCPL1U5KZZA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save this using Ctrl-S/CMD-S.&lt;/p&gt;
&lt;h3&gt;
  
  
  Writing the custom carousel menu code
&lt;/h3&gt;

&lt;p&gt;Go back to our custom widget so that we may implement the carousel menu.&lt;/p&gt;

&lt;p&gt;First, add the import for the carousel_slider dependency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AL7hsNBsaHMQYds5Q7NEo4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AL7hsNBsaHMQYds5Q7NEo4g.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a class called &lt;strong&gt;CarouselItem&lt;/strong&gt; and put it under &lt;strong&gt;_CarouselMenuState&lt;/strong&gt;. This class will hold each menu item from the JSON.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AeOalLl63M2TGkD4w7I0HKA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AeOalLl63M2TGkD4w7I0HKA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a list variable of CarouselItem’s.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A5rp8dfT4dRJWgYb4gKZCcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A5rp8dfT4dRJWgYb4gKZCcw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under the carousel item list, let’s override &lt;strong&gt;initState&lt;/strong&gt;. This method get’s called once when the widget first gets created.&lt;br&gt;
&lt;a href="https://api.flutter.dev/flutter/widgets/State/initState.html" rel="noopener noreferrer"&gt;&lt;strong&gt;initState method - State class - widgets library - Dart API&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Au5n2L5uin1-lxDZLVIevAQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Au5n2L5uin1-lxDZLVIevAQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under &lt;strong&gt;initState&lt;/strong&gt;, create a method to build our carousel widgets. This method doing 3 things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Iterating through each JSON Object in the JSON array.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creating a CarouselItem object with the current object’s value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adding this object to the carouselItems list.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2324%2F1%2Awm18eDtrboXH__zzUjut1Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2324%2F1%2Awm18eDtrboXH__zzUjut1Q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s change our build method to return the carousel_slider.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2528%2F1%2AZyCuxlOie01QONuCe0nS3A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2528%2F1%2AZyCuxlOie01QONuCe0nS3A.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that I have &lt;strong&gt;context.pushNamed(route);&lt;/strong&gt; commented out. This is the code FlutterFlow uses, but in the online editor, it will give you errors when compiling but will work when downloading the project.&lt;/p&gt;

&lt;p&gt;There are some workarounds to get it to run on the Flutter Flow platform. Essentially, after you launch the app in test mode, uncomment the code, save it, and click instant reload.&lt;/p&gt;

&lt;p&gt;Save and compile what we have so far.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting up screens to run our custom widget
&lt;/h3&gt;

&lt;p&gt;Next, go to the &lt;strong&gt;Widget Tree&lt;/strong&gt; tab to create our screens.&lt;/p&gt;

&lt;p&gt;Create four screens. One that has our custom widget and three others that the carousel items will navigate to. These are the names that you will use as the route in the custom JSON state.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AiD5gnsK1cGIZUnnZOzrz5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AiD5gnsK1cGIZUnnZOzrz5w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the page/screen you want your custom widget, go to the UI Builder and drag and drop the custom widget.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AiIPc7v-Ml9bRFD9N20VaYw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AiIPc7v-Ml9bRFD9N20VaYw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are my settings for the custom widget.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AShVKRltfQHCAQ-4p-9aGig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AShVKRltfQHCAQ-4p-9aGig.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice I set the JSON variable from our local state JSON variable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AjeWguE7jqhtaDevuwfS9wA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AjeWguE7jqhtaDevuwfS9wA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the project and click the run in test mode button on the top right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Atp19iCRvN_p_PfQ5npEpIA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Atp19iCRvN_p_PfQ5npEpIA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To test clicking the menu items, go back to the custom code and uncomment it. Save and then compile it. Go back to Test Mode and click instant reload. This will work fine when you download the code.&lt;/p&gt;

&lt;p&gt;Here is the full source code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


</description>
      <category>flutter</category>
      <category>dart</category>
      <category>androiddev</category>
      <category>mobile</category>
    </item>
    <item>
      <title>AWS Fundamentals: Create an Account, Billing Alarm, and Budgets</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Tue, 26 Sep 2023 13:00:00 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/aws-fundamentals-create-an-account-billing-alarm-and-budgets-1n1b</link>
      <guid>https://dev.to/cmcoffeedev/aws-fundamentals-create-an-account-billing-alarm-and-budgets-1n1b</guid>
      <description>&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;AWS Fundamentals: Create an Account, Billing Alarm, and Budgets&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;I am creating a series of articles on my AWS learning journey. I will create a full-stack project to keep me interested in learning and use those skills to get certified. I also plan to do the same thing on Azure, and Google Cloud in the future.&lt;/p&gt;

&lt;p&gt;In this first article, I will discuss setting up an AWS account, billing alarm, and AWS budget to ensure you never spend anything if you follow along. I also believe AWS gives you additional free credits beyond their free tier for the first year.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an AWS account
&lt;/h3&gt;

&lt;p&gt;Let’s start by creating an AWS account. Click on the link below.&lt;br&gt;
&lt;a href="https://aws.amazon.com/"&gt;&lt;strong&gt;Cloud Computing Services - Amazon Web Services (AWS)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, you will see an orange Create Account button at the top right of the page. Click this button to create an account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6lytTxDb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ApdBNFF1DEnfu_y2qUgGP9A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6lytTxDb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ApdBNFF1DEnfu_y2qUgGP9A.png" alt="" width="532" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable Billing Alerts
&lt;/h3&gt;

&lt;p&gt;You can use AWS Cloudwatch to monitor your AWS usage and get alerts when you exceed your intended budget. You can use Billing Alarms and AWS Budgets to notify you once you have exceeded your budget.&lt;/p&gt;

&lt;p&gt;First, you need to enable billing alerts in your billing preferences.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search for Billing or go to the AWS billing page. &lt;a href="https://console.aws.amazon.com/billing/home?#/"&gt;https://console.aws.amazon.com/billing/home?#/&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eTklocoo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3732/1%2A3nT2MhMTONipqx61Qsft3A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eTklocoo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3732/1%2A3nT2MhMTONipqx61Qsft3A.png" alt="Search for Billing" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On the left menu, under Preferences, choose &lt;strong&gt;Billing Preferences.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NGyNAne7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AYcFF2DCmcVes8ZCB97Vp6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NGyNAne7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AYcFF2DCmcVes8ZCB97Vp6g.png" alt="" width="256" height="809"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check &lt;strong&gt;Receive Billing Alerts **and Click **Save preferences&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--daG9ZbkG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ATiWah2onqzuT-U-_y_ciCA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--daG9ZbkG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ATiWah2onqzuT-U-_y_ciCA.png" alt="" width="798" height="984"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is also the documentation for enabling this in case it changes.&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html#turning_on_billing_metrics"&gt;&lt;strong&gt;Creating a billing alarm to monitor your estimated AWS charges&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Billing Alarm
&lt;/h3&gt;

&lt;p&gt;Now let’s create an AWS Billing Alarm. We must do this under AWS Cloudwatch.&lt;/p&gt;

&lt;p&gt;Search for &lt;strong&gt;Cloudwatch&lt;/strong&gt; or go to &lt;a href="https://console.aws.amazon.com/cloudwatch/"&gt;https://console.aws.amazon.com/cloudwatch/&lt;/a&gt; . You may also &lt;strong&gt;star&lt;/strong&gt; the service when searching to make it a bookmark.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aGCTY7XR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2988/1%2AgryJc1NSiUwy-uTKsfR4hw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aGCTY7XR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2988/1%2AgryJc1NSiUwy-uTKsfR4hw.png" alt="" width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the top right, directly left of your name, make sure the region is &lt;strong&gt;N. Virginia&lt;/strong&gt;, because billing metric data is only stored in this region.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sJ7SEzAY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AkoljN6wO2Lcy67_XVAzE6A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sJ7SEzAY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AkoljN6wO2Lcy67_XVAzE6A.png" alt="" width="228" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;All Alarms&lt;/strong&gt; on the left-hand menu.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yvtuXT9n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Af29ndi3xsmrZ32w-5RT56Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yvtuXT9n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Af29ndi3xsmrZ32w-5RT56Q.png" alt="" width="556" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create Alarm&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F9QtvywB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Ams4iQkGNJksaqAWPFmdx3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F9QtvywB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Ams4iQkGNJksaqAWPFmdx3w.png" alt="" width="570" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The button above only shows when you haven’t created any alarms.&lt;/p&gt;

&lt;p&gt;There is also an orange &lt;strong&gt;Create alarm&lt;/strong&gt; button that you will use when creating additional alarms. This button is at the top right of the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LV99bYW3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AV_M3Jvgxoqx9PNIHaYv0Hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LV99bYW3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AV_M3Jvgxoqx9PNIHaYv0Hg.png" alt="" width="764" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Select Metric&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YlOnQ2gA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3372/1%2AESRcUeT2dmYtQPtGvTRpzA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YlOnQ2gA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3372/1%2AESRcUeT2dmYtQPtGvTRpzA.png" alt="" width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Billing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7gMnukeN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A0r0Ebi8JGy9lGwtVXGpGKg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7gMnukeN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A0r0Ebi8JGy9lGwtVXGpGKg.png" alt="" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Total Estimated Charge&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---Y34JbvZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AIrMMRqSgx6Cx9RqCvLfqlw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---Y34JbvZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AIrMMRqSgx6Cx9RqCvLfqlw.png" alt="" width="800" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check the &lt;strong&gt;EstimatedCharges&lt;/strong&gt; metric.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--80Z4lba5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AOijxUYmBlUsaWqs813TwxQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--80Z4lba5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AOijxUYmBlUsaWqs813TwxQ.png" alt="" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Select metric&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B5GmWoEv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AaDUi9eXQRn6Qa0PgkdrXwA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B5GmWoEv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AaDUi9eXQRn6Qa0PgkdrXwA.png" alt="" width="500" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From here, in &lt;strong&gt;Step 1&lt;/strong&gt;, you can adjust the metric name and condition for the alert.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Uq3b9lqk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4124/1%2A9ApwmGIczwWLShw9QXLHfQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Uq3b9lqk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4124/1%2A9ApwmGIczwWLShw9QXLHfQ.png" alt="" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By default, the &lt;strong&gt;Threshold Type&lt;/strong&gt; is &lt;strong&gt;Static,&lt;/strong&gt; and the condition is Greater than. You should give a threshold value such as 0, so the alarm will trigger when you get billed anything over the free tier. Now click next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---JpUpnuu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3228/1%2APXsGU3IdN7Xh8GBBt9ODlQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---JpUpnuu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3228/1%2APXsGU3IdN7Xh8GBBt9ODlQ.png" alt="" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In step 2, the Notification page, the default &lt;strong&gt;Alarm state trigger&lt;/strong&gt; is &lt;strong&gt;In Alarm&lt;/strong&gt;. We can keep this value. We must also select or create an SNS(Simple Notifications Service) topic that will receive the notification.&lt;/p&gt;

&lt;p&gt;If you create a new SNS topic, give it a name and the email where you want the notification to be received. Now click create Create Topic and wait for it to be created.&lt;/p&gt;

&lt;p&gt;Make sure to use a valid email because you will need to confirm the SNS subscription.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GMJ7OwvF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3992/1%2A93Js06573VORdTTuR8gAUA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GMJ7OwvF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3992/1%2A93Js06573VORdTTuR8gAUA.png" alt="" width="800" height="638"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In step 3, give the alarm a name and description.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d0msEBqS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4212/1%2AYU6x4hcWxmhxjwW_ceirAg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d0msEBqS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4212/1%2AYU6x4hcWxmhxjwW_ceirAg.png" alt="" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In step 4, preview your alarm settings and ensure they are correct.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3VpoRqSG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4324/1%2AZRjosJpNm3q0X4ixk8VBMg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3VpoRqSG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4324/1%2AZRjosJpNm3q0X4ixk8VBMg.png" alt="" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yzP0Bsi4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3168/1%2AfAugW8-Umva45Dp_7PtFrA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yzP0Bsi4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3168/1%2AfAugW8-Umva45Dp_7PtFrA.png" alt="" width="800" height="899"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click **Create alarm **at the bottom right. It will take a couple of minutes to finish.&lt;/p&gt;

&lt;p&gt;I’ve linked the documentation below for reference.&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html"&gt;&lt;strong&gt;Creating a billing alarm to monitor your estimated AWS charges&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating an AWS Budget
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Currently, you get 2 budgets for free.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Search and go to **Billing **or go to the AWS billing page. &lt;a href="https://console.aws.amazon.com/billing/home?#/"&gt;https://console.aws.amazon.com/billing/home?#/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--31l6QxFH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3200/1%2Av6UrG1J_-MPf99aN4xJd-g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--31l6QxFH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3200/1%2Av6UrG1J_-MPf99aN4xJd-g.png" alt="" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under &lt;strong&gt;Cost Management&lt;/strong&gt; click &lt;strong&gt;Budgets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VaJUdcf0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A5hVjAGiLu4w20cFxfhUDww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VaJUdcf0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A5hVjAGiLu4w20cFxfhUDww.png" alt="" width="300" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the orange &lt;strong&gt;Create Budget&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zh2FdX92--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A0P8yOjblF2mqUgK4lxcKXg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zh2FdX92--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A0P8yOjblF2mqUgK4lxcKXg.png" alt="" width="778" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, a template is selected. We can use this version for now. You have multiple template options, but we will keep the default, &lt;strong&gt;Zero spend budget&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UIHf3AoM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3728/1%2AhLJDeKxRH5zXx-7YQlI8tg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UIHf3AoM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3728/1%2AhLJDeKxRH5zXx-7YQlI8tg.png" alt="" width="800" height="761"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give the budget a name, amount, and email recipients.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Create budget&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vzMNnwCY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AiMLxiOYu7YM_HbYtpXG2hA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vzMNnwCY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AiMLxiOYu7YM_HbYtpXG2hA.png" alt="" width="608" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you have created an AWS account and set up your AWS budget and Billing alarms.&lt;/p&gt;

&lt;p&gt;In the following article, I will show you how to create an AWS IAM user and install the AWS CLI. We will use the AWS CLI to create an AWS Budget and Billing alarm.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>linux</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Leetcode: Linked List Cycle (Kotlin)</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Tue, 26 Sep 2023 01:30:00 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/leetcode-linked-list-cycle-kotlin-4oo</link>
      <guid>https://dev.to/cmcoffeedev/leetcode-linked-list-cycle-kotlin-4oo</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CuXbLQIP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2560/1%2Ap874AqEunZ_1xPdCxBhGQA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CuXbLQIP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2560/1%2Ap874AqEunZ_1xPdCxBhGQA.png" alt="" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an easy Leetcode LinkedList question. I will go over my thought process for solving this. For this, we will use Floyd’s Cycle Detection algorithm.&lt;br&gt;
&lt;a href="https://leetcode.com/problems/linked-list-cycle/"&gt;&lt;strong&gt;Linked List Cycle - LeetCode&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Brainstorm
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Define two pointers — slow and fast. Initialize both of them to the head of the linked list.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move the slow pointer one step at a time and the fast pointer two steps at a time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At each step, check if slow and fast pointers are equal. If they are equal at some point, then a cycle exists in the linked list.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the fast pointer reaches the end of the list (i.e., it becomes null), then there is no cycle in the list.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * Example:
 * var li = ListNode(5)
 * var v = li.`val`
 * Definition for singly-linked list.
 * class ListNode(var `val`: Int) {
 *     var next: ListNode? = null
 * }
 */

class Solution {
    fun hasCycle(head: ListNode?): Boolean {
       var slow = head
       var fast = head

       while(fast != null &amp;amp;&amp;amp; fast.next != null){
           slow = slow?.next
           fast = fast?.next?.next

           if(slow == fast){
               return true
           }
       }

       return false
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>leetcode</category>
      <category>kotlin</category>
      <category>androiddev</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Adding Google Maps to the Keith Lee food app (React.js)</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Sun, 02 Apr 2023 02:03:55 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/adding-google-maps-to-the-keith-lee-food-app-reactjs-93i</link>
      <guid>https://dev.to/cmcoffeedev/adding-google-maps-to-the-keith-lee-food-app-reactjs-93i</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0dnWmk0D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2APY4ZtSzNZqfG9vfVTJ9yNw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0dnWmk0D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2APY4ZtSzNZqfG9vfVTJ9yNw.png" alt="" width="400" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the previous article, I wrote about creating a Keith Lee food app using React.js and Firebase.&lt;br&gt;
&lt;a href="https://cmcoffee.dev/creating-a-keith-lee-food-app-w-react-js-chatgpt-11ac5ee67b8c"&gt;&lt;strong&gt;Creating a Keith Lee Food App w/ React.js &amp;amp; ChatGPT&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I will show you how I used the Google Maps Javascript SDK to display the list of restaurants on a map.&lt;br&gt;
&lt;a href="https://developers.google.com/maps/documentation/javascript"&gt;&lt;strong&gt;Google Maps Platform Documentation | Maps JavaScript API | Google Developers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have discontinued using Firebase and moved to Netlify for hosting and Supabase for the backend. I will create an article on my steps to migrate away from Firebase to Supabase.&lt;br&gt;
&lt;a href="https://www.netlify.com/"&gt;&lt;strong&gt;Develop and deploy websites and apps in record time | Netlify&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://supabase.com/"&gt;&lt;strong&gt;The Open Source Firebase Alternative | Supabase&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Enabling the Google Maps Javascript SDK
&lt;/h3&gt;

&lt;p&gt;We are going to follow along with the documentation from Google.&lt;br&gt;
&lt;a href="https://developers.google.com/maps/documentation/javascript/cloud-setup"&gt;&lt;strong&gt;Set up your Google Cloud project | Maps JavaScript API | Google Developers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a Google Project. Click on the blue &lt;strong&gt;Create new project&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dmJC_TIW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3488/1%2AGIpnzZEgrvdyq13eRawMVQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dmJC_TIW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3488/1%2AGIpnzZEgrvdyq13eRawMVQ.png" alt="" width="800" height="681"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill out the form and click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wIXABRqA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2252/1%2Aztzon1O68JPuJ54rEYZ8UA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wIXABRqA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2252/1%2Aztzon1O68JPuJ54rEYZ8UA.png" alt="" width="800" height="742"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to enable Google Maps for our project. Go to the following link and click &lt;strong&gt;Enable the Maps Javascript API&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://developers.google.com/maps/documentation/javascript/cloud-setup#enabling-apis"&gt;&lt;strong&gt;Set up your Google Cloud project | Maps JavaScript API | Google Developers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r2y3mRBT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3752/1%2AV2XMu8_jUBnDm6Ac7Fnr7g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r2y3mRBT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3752/1%2AV2XMu8_jUBnDm6Ac7Fnr7g.png" alt="" width="800" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The button below will initially state &lt;strong&gt;Enable&lt;/strong&gt;. Click it then it will say &lt;strong&gt;Manage. **Now click **Manage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OnjuxLjh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AbZwVm1xBV0B2kQswdyASTg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OnjuxLjh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AbZwVm1xBV0B2kQswdyASTg.png" alt="" width="800" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click Credentials on the left hand side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AQckjrrv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AzGgJWtLVQrSc40TC2v29dA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AQckjrrv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AzGgJWtLVQrSc40TC2v29dA.png" alt="" width="494" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see your Google Maps API key. We will need this soon. You may also restrict the API key to localhost:3000. When you get a domain, you may add it to the list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0_gg5H-T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4288/1%2A6kcESUDS91l958Kww_8vIg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0_gg5H-T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4288/1%2A6kcESUDS91l958Kww_8vIg.png" alt="" width="800" height="79"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will first need to load the Javascript API in our React project. Go to the following link. We will follow along with this documentation.&lt;br&gt;
&lt;a href="https://developers.google.com/maps/documentation/javascript/load-maps-js-api"&gt;&lt;strong&gt;Load the Maps JavaScript API | Google Developers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am going to use the recommended Dynamic Library Import. Add the following Javascript code before the closing body tag in index.html&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  (g=&amp;gt;{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=&amp;gt;h||(h=new Promise(async(f,n)=&amp;gt;{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=&amp;gt;"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src='https://maps.${c}apis.com/maps/api/js?'+e;d[q]=f;a.onerror=()=&amp;gt;h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=&amp;gt;r.add(f)&amp;amp;&amp;amp;u().then(()=&amp;gt;d[l](f,...n))})({
    key: "YOUR_API_KEY_HERE",
    v: "weekly",
    libraries: ["marker", "maps"]
    // Add other bootstrap parameters as needed, using camel case.
    // Use the 'v' parameter to indicate the version to load (alpha, beta, weekly, etc.)
  });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Notice we are adding the &lt;strong&gt;marker&lt;/strong&gt; and &lt;strong&gt;maps&lt;/strong&gt; libraries. Make sure to add your API key here.&lt;/p&gt;

&lt;p&gt;Now let’s create a new React functional component. We can also copy the firebase code from the previous article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import {Box} from "@mui/material";


    const config = {
      // Your Firebase project's config object goes here
    };

    firebase.initializeApp(config);
    const db = firebase.firestore();

    const RestaurantMap = () =&amp;gt; {




        return &amp;lt;Box
            sx={{
                height: '100vh',
                width: '100%'
            }}
            id="map"
        &amp;gt;

        &amp;lt;/Box&amp;gt;


    }

    export default RestaurantMap;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run the code and it will show a blank Google map.&lt;/p&gt;

&lt;p&gt;You can run the code and it will show a blank Google map.&lt;/p&gt;

&lt;p&gt;We will then load the markers on the google map. Add this right above the return. Note I have comments of numbers. I will detail those steps under the code.&lt;/p&gt;

&lt;p&gt;Also, we are querying firebase again. We could use redux-toolkit to load and save the data only when needed. For now, we will load it again. In the future, I may add redux-toolkit. It would only take a few mins to implement.&lt;br&gt;
&lt;a href="https://redux-toolkit.js.org/tutorials/quick-start"&gt;&lt;strong&gt;Quick Start | Redux Toolkit&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    useEffect(() =&amp;gt; {
        // Get data from the 'tiktoks' collection in Firestore
       const google = window.google; // 1
       const {Map} = await google.maps.importLibrary("maps"); // 2
       const map = new Map(document.getElementById("map"), {  
                        center: {lat: 36.188110, lng: -115.176468},
                        zoom: 12,
                   });
       db.collection('tiktoks').get() // 3
          .then(snapshot =&amp;gt; {
                const data = snapshot.docs.map(doc =&amp;gt; doc.data()); // Each item in firebase

                const position = {lat: place.lat, lng: place.lng};


                const marker = new google.maps.Marker({ // 4
                     map: map,
                     position: position,
                     title: place.name,
                });

                // ...Retrieve variables below depending on what you want to do 

                const information = new google.maps.InfoWindow({ // 5
                    content: '
                             &amp;lt;h4&amp;gt;${place.name}&amp;lt;/h4&amp;gt;
                             &amp;lt;div&amp;gt;
                                 ${address}
                             &amp;lt;/div&amp;gt;
                             ${dir}
                             ${callDiv}
                             &amp;lt;hr&amp;gt;
                             &amp;lt;div&amp;gt;
                                 &amp;lt;a href="${shareHref}" target="_blank"/&amp;gt;Share&amp;lt;/a&amp;gt;
                             &amp;lt;/div&amp;gt;
                             &amp;lt;hr&amp;gt;
                              &amp;lt;div&amp;gt;
                                 &amp;lt;a href="${tiktokUrl}" target="_blank"/&amp;gt;Watch Review&amp;lt;/a&amp;gt;
                             &amp;lt;/div&amp;gt;
                             ${orderUrl}
                             '
                });

                marker.addListener('click', function () { // 6
                    information.open(map, marker);
                });



          })
          .catch(error =&amp;gt; {
            console.log(error);
          });
      }, []);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Add the google library&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Import the maps library from google and create Map object. I have this centered in Las Vegas, since this is where most of the food reviews happen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get the list of items from firebase&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the Google Marker for the current item&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the InfoWindow to the Google Marker. This is the popup that shows when you click the Google Marker.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add a click listener to the marker to make the InfoWindow popup when you show it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can refer to the documentation for further customization:&lt;br&gt;
&lt;a href="https://developers.google.com/maps/documentation/javascript/adding-a-google-map"&gt;&lt;strong&gt;Add a Google Map with a Marker to Your Website | Maps JavaScript API | Google Developers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few days after creating this map with the list of items, I found someone created a Google MyMaps on reddit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nqLdufkw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.reddit.com/r/vegaslocals/comments/10pqllx/i_made_a_google_map_of_the_places_keith_lee_has/" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nqLdufkw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.reddit.com/r/vegaslocals/comments/10pqllx/i_made_a_google_map_of_the_places_keith_lee_has/" alt="**Reddit Keith Lee map**" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I liked it so much, I decided to add it to the web app on a separate page&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2CKLoMGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A-eINJsjyJIvlOta_39_E5g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2CKLoMGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A-eINJsjyJIvlOta_39_E5g.png" alt="" width="400" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading. Let me know if any clarification is needed. You can find the Keith Lee food app at the following link:&lt;br&gt;
&lt;a href="https://keithleefood.com/"&gt;&lt;strong&gt;Keith Lee Food Reviews&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>googlemaps</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Creating a Keith Lee Food App w/ React.js &amp; ChatGPT</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Sun, 02 Apr 2023 01:55:29 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/creating-a-keith-lee-food-app-w-reactjs-chatgpt-2no5</link>
      <guid>https://dev.to/cmcoffeedev/creating-a-keith-lee-food-app-w-reactjs-chatgpt-2no5</guid>
      <description>&lt;h2&gt;
  
  
  Creating a Keith Lee Food App w/ React.js &amp;amp; ChatGPT
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HQThSF6Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A08tHsKBwZzaEzWsEyfrD-Q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HQThSF6Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A08tHsKBwZzaEzWsEyfrD-Q.jpeg" alt="" width="750" height="1210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0cW33Vdp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ALkcaUDXZkOOtN0B5B1OhyQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0cW33Vdp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ALkcaUDXZkOOtN0B5B1OhyQ.gif" alt="" width="480" height="826"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This personal project was inspired by watching Keith Lee and wanting to try the family-owned restaurants he reviewed on his platforms. I was initially using a spreadsheet to keep track of the names and addresses of the places.&lt;/p&gt;

&lt;p&gt;Here are his socials for reference:&lt;br&gt;
&lt;a href="https://linktr.ee/Keith_lee125"&gt;&lt;strong&gt;@keith_lee125 | Twitter, Instagram, TikTok | Linktree&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the weekend, I decided to hack together two simple React.js web apps to improve this process.&lt;/p&gt;

&lt;p&gt;UPDATE: Recently added maps and the ability to order food.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I have moved away from firebase, but the following steps will work. I have moved to Supabase for the backend and Netlify for hosting. These platforms are more cost-efficient. I will have articles detailing how to do this soon.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Set up Firebase Firestore
&lt;/h3&gt;

&lt;p&gt;I wanted to store this in a remote database. I chose to use Firebase so I could quickly put this together.&lt;/p&gt;

&lt;p&gt;You can create a new project by going to the firebase console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://console.firebase.google.com/"&gt;https://console.firebase.google.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once your project is created. Click on &lt;strong&gt;Add app.&lt;/strong&gt; It’s under your project name at the top center of the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3i4rMT-x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AaHQ7fJy47g8As5RrzYDXNw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3i4rMT-x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AaHQ7fJy47g8As5RrzYDXNw.png" alt="" width="314" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, choose the web platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PFsGcdHD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Aiv5OfWKZmH6vBOWAFtJdbQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PFsGcdHD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Aiv5OfWKZmH6vBOWAFtJdbQ.png" alt="" width="734" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give your web app a name and click Register app&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oOADuikU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2288/1%2AK48EhXn-hBXVIjZUtz-C3A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oOADuikU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2288/1%2AK48EhXn-hBXVIjZUtz-C3A.png" alt="" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it will give you instructions on how to install firebase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BABHgaI3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2876/1%2AMYT3CbD-DdOMUDLnzuy9jA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BABHgaI3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2876/1%2AMYT3CbD-DdOMUDLnzuy9jA.png" alt="" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will follow these instructions soon, but first, we need to create a react app. Keep this tab open. We will refer to it soon. Specifically, we will need the firebase config&lt;/p&gt;

&lt;p&gt;I also wanted ChatGPT to generate the boilerplate code. So let’s do that first.&lt;/p&gt;

&lt;h3&gt;
  
  
  ChatGPT
&lt;/h3&gt;

&lt;p&gt;I used ChatGPT to try to make this process easier. It gave a few incorrect code snippets, but this is also maybe because I’m using the latest versions of everything, and ChatGPT was only trained up to a certain time period.&lt;/p&gt;

&lt;p&gt;I only wanted to store the information from Keith Lee’s TikTok videos. So this includes the id used on the TikTok web app, the description used in the video, and embedding the TikTok video.&lt;/p&gt;

&lt;p&gt;This tool did help improve the process. Here was my first prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can you create a react frontend that reads data from firebase firestore. example code&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It then replied with this code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect } from 'react';
import firebase from 'firebase/app';
import 'firebase/firestore';

const config = {
  // Your Firebase project's config object goes here
};

firebase.initializeApp(config);
const db = firebase.firestore();

function App() {
  const [data, setData] = useState([]);

  useEffect(() =&amp;gt; {
    // Get data from the 'users' collection in Firestore
    db.collection('users').get()
      .then(snapshot =&amp;gt; {
        const data = snapshot.docs.map(doc =&amp;gt; doc.data());
        setData(data);
      })
      .catch(error =&amp;gt; {
        console.log(error);
      });
  }, []);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Users&amp;lt;/h1&amp;gt;
      &amp;lt;ul&amp;gt;
        {data.map(user =&amp;gt; (
          &amp;lt;li key={user.id}&amp;gt;{user.name}&amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Notice the comment &lt;strong&gt;// Your Firebase project’s config object goes here.&lt;/strong&gt; This is the **const firebaseObject code. **The screenshot cuts off the rest of the code, but here is an example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const firebaseConfig = {
  apiKey: "yourApiKey",
  authDomain: "projectid.firebaseapp.com",
  projectId: "projectid",
  storageBucket: "projectid.appspot.com",
  messagingSenderId: "77777777777",
  appId: "1:777777777777:web:ab7ag7v7a7",
  measurementId: "G-MEASUREMENTID"
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Create a new React App
&lt;/h3&gt;

&lt;p&gt;To use this code, we need to create a new react project. I created a new app using the following command&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app keith-lee-food
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After the react project is created, I installed the firebase SDK using the following command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save firebase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/firebase"&gt;&lt;strong&gt;firebase&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I want to note that I installed the latest firebase version using npm, so the code in the useEffect won’t work.&lt;/p&gt;

&lt;p&gt;We can follow the documentation to update this code. We could have also asked ChatGPT, and it may have known. Not sure how new this latest version of firebase is.&lt;br&gt;
&lt;a href="https://firebase.google.com/docs/firestore/quickstart#read_data"&gt;&lt;strong&gt;Get started with Cloud Firestore | Firebase&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the updated will look something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { collection, getDocs } from "firebase/firestore"; 

const querySnapshot = await getDocs(collection(db, "users"));
querySnapshot.forEach((doc) =&amp;gt; {
  console.log('${doc.id} =&amp;gt; ${doc.data()}');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Of course, we don’t have any data in the database, so it won’t return anything. We also will have a different collection name.&lt;/p&gt;

&lt;p&gt;This is the next prompt I gave ChatGPT:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;can you change the query to read an id and description and show a tiktok embed widget using the id. also show the description under that&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the code it replied with&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; import React, { useState, useEffect } from 'react';
import firebase from 'firebase/app';
import 'firebase/firestore';

const config = {
  // Your Firebase project's config object goes here
};

firebase.initializeApp(config);
const db = firebase.firestore();

function App() {
  const [data, setData] = useState([]);

  useEffect(() =&amp;gt; {
    // Get data from the 'tiktoks' collection in Firestore
    db.collection('tiktoks').get()
      .then(snapshot =&amp;gt; {
        const data = snapshot.docs.map(doc =&amp;gt; doc.data());
        setData(data);
      })
      .catch(error =&amp;gt; {
        console.log(error);
      });
  }, []);

  return (
    &amp;lt;div&amp;gt;
      {data.map(tiktok =&amp;gt; (
        &amp;lt;div key={tiktok.id}&amp;gt;
          &amp;lt;h1&amp;gt;{tiktok.description}&amp;lt;/h1&amp;gt;
          &amp;lt;iframe 
            src={'https://www.tiktok.com/embed/${tiktok.id}'}
            frameBorder="0" 
            allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 
            allowFullScreen 
          /&amp;gt;
        &amp;lt;/div&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It still gives the code we can’t use in the useEffect. We can give ChatGPT our code, but I just replaced it with the code mentioned earlier in the documentation.&lt;/p&gt;

&lt;p&gt;I took off the iframe because it loaded every video, leading to bad performance. It also auto-plays every time you scroll. &lt;strong&gt;autoplay&lt;/strong&gt; option for allow doesn’t cause this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Firebase Firestore with React
&lt;/h3&gt;

&lt;p&gt;Now we need to set enable Firestore on the Firebase console. Go back to the Firebase console and click Continue to console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--amZn5Vbf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AthcSxAORwhlfGTHF99WNOA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--amZn5Vbf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AthcSxAORwhlfGTHF99WNOA.png" alt="" width="746" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;Build&lt;/strong&gt; menu option on the left. Click Firestore Database&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1heerpy---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A7c4I69K9bfNr2b4zXMrj0A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1heerpy---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A7c4I69K9bfNr2b4zXMrj0A.png" alt="" width="460" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next screen, click Create database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lecFM7mI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AMPBNknC3Xe4fc6u788q0mQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lecFM7mI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AMPBNknC3Xe4fc6u788q0mQ.png" alt="" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now a popup will show asking us what mode we would like to start in. Keep it at &lt;strong&gt;Start in production mode&lt;/strong&gt;. Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7wJ4b_Kg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3240/1%2AiEB6OiyvYLMObLn5mc0Tgw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7wJ4b_Kg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3240/1%2AiEB6OiyvYLMObLn5mc0Tgw.png" alt="" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next will ask where we want the data stored. I kept it at this region and clicked enable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nkMFotGr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3244/1%2AQlL7nRI34AcU_0Cn8YYC9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nkMFotGr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3244/1%2AQlL7nRI34AcU_0Cn8YYC9w.png" alt="" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can add data through the console to quickly test our application. On this screen, click &lt;strong&gt;Start collection&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--00RtWiDE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A12S2DcWP7Zo_QPlPfxOZkw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--00RtWiDE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A12S2DcWP7Zo_QPlPfxOZkw.png" alt="" width="652" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give a collection id. I will use the id ChatGPT generated, &lt;strong&gt;tiktoks&lt;/strong&gt;. Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g20YrKdr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2800/1%2ARhl_JddI-8AiE5ILzeqUUg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g20YrKdr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2800/1%2ARhl_JddI-8AiE5ILzeqUUg.png" alt="" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can create a document. If you are unfamiliar with Firestore, this is a record in our collection.&lt;/p&gt;

&lt;p&gt;Using the TikTok website, we can figure out what information we need to save. For now, I will just save the id and description.&lt;/p&gt;

&lt;p&gt;Observe the following URL: &lt;a href="https://www.tiktok.com/@keith_lee125/video/7186098325475839278"&gt;https://www.tiktok.com/@keith_lee125/video/7186098325475839278&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Document ID and id field will be the long number at the end of the URL.&lt;/p&gt;

&lt;p&gt;If you go to the URL, it will go to one of Keith Lee’s videos. I copied the description from there. Click **Save **after adding your data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--st86KNTl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2760/1%2A-8yBQGkSL74ql2sKo_ZFHg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--st86KNTl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2760/1%2A-8yBQGkSL74ql2sKo_ZFHg.png" alt="" width="800" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to update the code ChatGPT gave to include the config and web 9 version of firebase. Here is an example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect } from 'react';
import { collection, getDocs } from "firebase/firestore"; 
import { initializeApp } from "firebase/app";
import { getFirestore } from 'firebase/firestore'

const config = {
  apiKey: "yourApiKey",
  authDomain: "projectid.firebaseapp.com",
  projectId: "projectid",
  storageBucket: "projectid.appspot.com",
  messagingSenderId: "77777777777",
  appId: "1:777777777777:web:ab7ag7v7a7",
  measurementId: "G-MEASUREMENTID"
};


const firebaseApp = initializeApp(config);
const db = getFirestore(firebaseApp);

function App() {
  const [data, setData] = useState([]);

  useEffect(() =&amp;gt; {
    // Get data from the 'tiktoks' collection in Firestore
      const querySnapshot = await getDocs(collection(db, "tiktoks"));
      querySnapshot.forEach((doc) =&amp;gt; {
          setData(doc.data());
      });
  }, []);

  return (
    &amp;lt;div&amp;gt;
      {data.map(tiktok =&amp;gt; (
        &amp;lt;div key={tiktok.id}&amp;gt;
          &amp;lt;h4&amp;gt;{tiktok.description}&amp;lt;/h4&amp;gt;
          &amp;lt;iframe 
            src={'https://www.tiktok.com/embed/${tiktok.id}'}
            frameBorder="0" 
            allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" 
            allowFullScreen 
          /&amp;gt;
        &amp;lt;/div&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I left the code for the iframe in here, but you can leave it if you want. I also changed the h1 to h4.&lt;/p&gt;

&lt;p&gt;In the root directory of this project, run this in the terminal to start your application.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I then wanted to show a button to get directions. For this, I wanted to add latitude and longitude in the database.&lt;/p&gt;

&lt;p&gt;I gave another request to ChatGPT as follows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;can you give example if we had longitude and latitude from firebase as well and show a button to get directions. can you show example code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It replied :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sure, here is an example of how you can modify the code to read longitude and latitude from Firestore, and show a button that, when clicked, opens the default maps application with the location pre-populated as the destination:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect } from 'react';
import firebase from 'firebase/app';
import 'firebase/firestore';

const config = {
  // Your Firebase project's config object goes here
};

firebase.initializeApp(config);
const db = firebase.firestore();

function App() {
  const [data, setData] = useState([]);

  useEffect(() =&amp;gt; {
    // Get data from the 'locations' collection in Firestore
    db.collection('tiktok').get()
      .then(snapshot =&amp;gt; {
        const data = snapshot.docs.map(doc =&amp;gt; doc.data());
        setData(data);
      })
      .catch(error =&amp;gt; {
        console.log(error);
      });
  }, []);

  return (
    &amp;lt;div&amp;gt;
      {data.map(tiktok =&amp;gt; (
        &amp;lt;div key={tiktok.id}&amp;gt;
          &amp;lt;h1&amp;gt;{location.name}&amp;lt;/h1&amp;gt;
          &amp;lt;button onClick={() =&amp;gt; {
            window.open('https://www.google.com/maps/dir/?api=1&amp;amp;destination=${tiktok.latitude},${tiktok.longitude}');
          }}&amp;gt;Get Directions&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will open Google Maps website on desktop and iPhone devices. It will open the Google Maps app on Android Devices.&lt;/p&gt;

&lt;p&gt;I wanted it to open Apple Maps app on iOS devices. I then asked ChatGPT to do this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;can you change the html to consider if the user is on an apple device. can you show example code&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ChatGPT replied with this code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect } from 'react';
import firebase from 'firebase/app';
import 'firebase/firestore';

const config = {
  // Your Firebase project's config object goes here
};

firebase.initializeApp(config);
const db = firebase.firestore();

function App() {
  const [data, setData] = useState([]);
  const [isApple, setIsApple] = useState(false);

  useEffect(() =&amp;gt; {
    // Get data from the 'locations' collection in Firestore
    db.collection('tiktoks').get()
      .then(snapshot =&amp;gt; {
        const data = snapshot.docs.map(doc =&amp;gt; doc.data());
        setData(data);
      })
      .catch(error =&amp;gt; {
        console.log(error);
      });

    // Check if the user is on an Apple device
    const isAppleDevice = /iPad|iPhone|iPod/.test(navigator.userAgent);
    setIsApple(isAppleDevice);
  }, []);

  return (
    &amp;lt;div&amp;gt;
      {data.map(tiktok =&amp;gt; (
        &amp;lt;div key={tiktok.id}&amp;gt;
          &amp;lt;h1&amp;gt;{tiktok.name}&amp;lt;/h1&amp;gt;
          {isApple ? (
            &amp;lt;a href={'maps://?q=${tiktok.latitude},${tiktok.longitude}'}&amp;gt;Get Directions&amp;lt;/a&amp;gt;
          ) : (
            &amp;lt;button onClick={() =&amp;gt; {
              window.open('https://www.google.com/maps/dir/?api=1&amp;amp;destination=${tiktok.latitude},${tiktok.longitude}');
            }}&amp;gt;Get Directions&amp;lt;/button&amp;gt;
          )}
        &amp;lt;/div&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I wanted to move this location logic to a function.&lt;/p&gt;

&lt;p&gt;This is my updated html:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    place.lat === undefined ? &amp;lt;div&amp;gt;&amp;lt;/div&amp;gt; :
    &amp;lt;button onClick={() =&amp;gt; goToMap(tiktok)}&amp;gt;Get Directions&amp;lt;/button&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I’m using a ternary operator to check if lat (latitude) is set. If it is not set, I will show an empty div element. If we have lat it will show the button. The button now calls a function that passes the &lt;strong&gt;tiktok&lt;/strong&gt; object.&lt;/p&gt;

&lt;p&gt;Here is the &lt;strong&gt;goToMap&lt;/strong&gt; function.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; const goToMap = (tiktok) =&amp;gt; {
        if (isApple) {
            window.open('maps://?q=${tiktok.lat},${tiktok.lng}');
        } else {
            window.open('https://www.google.com/maps/dir/?api=1&amp;amp;destination=${tiktok.lat},${tiktok.lng}');
        }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now let’s add latitude and longitude fields to the firestore document we created earlier. I found the latitude and longitude using google maps. Click Add field, and add the following lat and lng fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lat&lt;/strong&gt;: 36.11337630000001&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lng&lt;/strong&gt;: -115.3094725&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2t-xCuLv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2212/1%2AyMB1UvwKzXzWHCLDFv_ArQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2t-xCuLv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2212/1%2AyMB1UvwKzXzWHCLDFv_ArQ.png" alt="" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Re-run or refresh the web apps page, and you should now be able to get directions to the location.&lt;/p&gt;

&lt;p&gt;Since the embedded TikTok wasn’t going to be a good solution, I wanted to add a button to go to the video to watch the review again and get ideas of the kinds of food they have.&lt;/p&gt;

&lt;p&gt;I copied and created a new button above the first button for this.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;lt;button onClick={() =&amp;gt; watchVideo(tiktok.id)}&amp;gt;
     Watch Video
 &amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then &lt;strong&gt;watchVideo&lt;/strong&gt; function will look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const watchVideo = (id) =&amp;gt; {
    window.open('https://www.tiktok.com/@keith_lee125/video/${id}', '_blank', 'noreferrer');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I’m basically recreating the url we based all of the data off of. Re-run the app to get an idea of how it works.&lt;/p&gt;

&lt;p&gt;When clicking this button on the desktop, it will go to the videos page on the TikTok website. On iOS and Android devices, it will deep link to the TikTok app if you have it installed.&lt;/p&gt;

&lt;p&gt;A couple of more things to note. For the design, I used the react Material UI package. I won’t go over the steps how, but I may in a future post.&lt;br&gt;
&lt;a href="https://mui.com/"&gt;&lt;strong&gt;MUI: The React component library you always wanted&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also created an admin react app to easily create and edit info.&lt;/p&gt;

&lt;p&gt;I won’t go over this in this article but may create another one detailing those steps. For now, I’ll give a high-level overview of how I achieved this.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a new react app and copy the files from this project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installed react-router to go to the &lt;strong&gt;edit&lt;/strong&gt; and &lt;strong&gt;create new&lt;/strong&gt; page. &lt;a href="https://reactrouter.com/en/main"&gt;https://reactrouter.com/en/main&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to the Google Developers Console and enable the Google Places API for this project, which was created by firebase. Also, get the API key. &lt;a href="https://console.developers.google.com/"&gt;https://console.developers.google.com/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Used code from here to implement the Google Places API. &lt;a href="https://github.com/Gapur/google-place-autocomplete"&gt;https://github.com/Gapur/google-place-autocomplete&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once we get a place object from the autocomplete component, we can easily get info such as latitude, longitude, address, etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vGNA3_xX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A0wJGcKtHdIPwFi9RYH0Cow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vGNA3_xX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A0wJGcKtHdIPwFi9RYH0Cow.png" alt="" width="400" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My current version of the Keith Lee Food web app can be found at &lt;a href="https://keithleefood.com"&gt;https://keithleefood.com&lt;/a&gt;. Would you try it? Rate it 1–10!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>chatgpt</category>
      <category>firebase</category>
    </item>
    <item>
      <title>Leetcode: Symmetric Tree (Kotlin)</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Fri, 25 Mar 2022 02:16:34 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/leetcode-symmetric-tree-kotlin-1m3o</link>
      <guid>https://dev.to/cmcoffeedev/leetcode-symmetric-tree-kotlin-1m3o</guid>
      <description>&lt;p&gt;Symmetric Tree is an “Easy” tagged Leetcode problem. The problem states “Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center).”&lt;/p&gt;

&lt;p&gt;They give us two examples:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MIwCXgAR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zn2t37czado2vr8y1lnt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MIwCXgAR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zn2t37czado2vr8y1lnt.png" alt="Image description" width="800" height="1479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Brainstorming:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can have a queue to check if the root’s left and right children are identical.&lt;/p&gt;

&lt;p&gt;These are the steps we can take to arrive at our solution:&lt;br&gt;
Create a queue and add the root twice to the queue.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;As long as there is a TreeNodes in the queue, we will take two TreeNodes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If they are both null, we have arrived at null leaf nodes, so continue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, if either node is null, we will return false since we already are checking if both are null beforehand. This is similar to the given Example 2.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lastly, we also need to check if the values are the same. Of course, if the values are not the same, they are not symmetric.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We will add each of the two current nodes opposite nodes to the queue.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Codelab version of this solution: &lt;br&gt;
&lt;a href="https://cmcoffeedev.com/codelabs/leetcode-symmetric-tree/index.html#0"&gt;https://cmcoffeedev.com/codelabs/leetcode-symmetric-tree/index.html#0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Video Solution: &lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/SwPFOnS-P4Y"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>leetcode</category>
      <category>algorithms</category>
      <category>programming</category>
    </item>
    <item>
      <title>Leetcode — Kth Smallest Element in a BST (Kotlin)</title>
      <dc:creator>Christopher Coffee</dc:creator>
      <pubDate>Fri, 25 Mar 2022 02:01:30 +0000</pubDate>
      <link>https://dev.to/cmcoffeedev/leetcode-kth-smallest-element-in-a-bst-kotlin-4m9</link>
      <guid>https://dev.to/cmcoffeedev/leetcode-kth-smallest-element-in-a-bst-kotlin-4m9</guid>
      <description>&lt;p&gt;This is a medium Leetcode problem that wants you to find the kth smallest value (1-indexed) of every value in the Binary Search Tree. I will show you two approaches I took to solve this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/kth-smallest-element-in-a-bst/"&gt;https://leetcode.com/problems/kth-smallest-element-in-a-bst/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First I will show you the problem statement, examples and constraints given. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cMh3zASf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nq3n8v49u0zooojrjauo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cMh3zASf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nq3n8v49u0zooojrjauo.png" alt="Image description" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7gfV0od7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tb0dzuakogvvr311tr41.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7gfV0od7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tb0dzuakogvvr311tr41.png" alt="Image description" width="750" height="840"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--51bx6FG2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a69j1j1kepjybaidrpxf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--51bx6FG2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a69j1j1kepjybaidrpxf.png" alt="Image description" width="800" height="768"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e9GrQJnw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1pldj3p1dnev2olgto66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e9GrQJnw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1pldj3p1dnev2olgto66.png" alt="Image description" width="596" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since this is a Binary Search Tree we can do an in-order traversal to get the values sorted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recursive Inorder Traversal&lt;/strong&gt;&lt;br&gt;
For the recursive inorder solution we can create an ArrayList of Int and pass it to our inorderTraversal function. We can add the values to the list at each recursive call.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create an ArrayList of Int and pass it to our inorderTraversal function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For the inorderTraversal function, we will have a base case that returns if the tree node passed is null.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the values to the list at each recursive call.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Return list[k-1] as our answer. They mention “k” starts at 1 indexed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Iterative Inorder Traversal&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a stack of nullable TreeNode&lt;br&gt;
root and k are immutable so we need to create mutable copies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can create a variable called temp or current as a copy for the root TreeNode. We can use indexToFind as a copy for k.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We will have nested while loops. The outer most while-loop will check if temp is null or the stack is empty.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The inner while loop will traverse all of temps left children and push them to the stack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After traversing the left children we will eventually hit a null node. We can then pop from the stack and set that node as temp, which will be the last leaf node we touched.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can pre decrement the indexToFind variable each time we get to this point. When the value is 0, we have found the index we are looking for so we can return the value. Set temp to temp’s right child.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Alternatively we can add the values to a list and return list[k-1] as we did in the recursive traversal.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Codelab version of this solution: &lt;a href="https://cmcoffeedev.com/codelabs/leetcode-kth-smallest/index.html?index=..%2F..index#0"&gt;https://cmcoffeedev.com/codelabs/leetcode-kth-smallest/index.html?index=..%2F..index#0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Video Solution:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/hujtxlzHgQk"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>kotlin</category>
      <category>algorithms</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
