My very simple but functional, Bhagavad Gita Next.js web app with minimal code and coding complexity, shared as open-source free-software; Notes

Last updated on 29 Jul 2024
Minor update on 1 Oct. 2024

Note

Improved version with regular web app UI deployed at: https://gita-rsi.vercel.app/
About latest version of regular web app as of 1 Oct. 2024: Gita web app (Next.js, open source) v1.4.1 .
About first incremental version of regular web app on top of this Very Simple Gita app: Gita Web App v1.0 (Open Source), Pathway to Self-Learn Next.js Web Dev with Tailwind CSS and TypeScript

====================================

Quick Info (about Very Simple Gita web app)


=================

Update for Version 2.0

This version adds to earlier version 1.0, the feature of going to a user specified chapter and optionally verse. It adds a little complexity to the app but not too much. Further, this little complexity is limited to two components (Navbar and its child SelectChapterVerse) and some utility functions in one file (util.js). Some minor finishing touches were added like moving Navbar to app layout page and thus having common Navbar for all app pages, adding not-found pages and about page.
end-Update for Version 2.0

Version 1.0

This is a very simple but functional, open-source freeware, Bhagavad Gita web app I wrote recently. It uses Next.js and Apollo Client to retrieve Bhagavad Gita chapters and verses data from a GraphQL endpoint: https://gql.bhagavadgita.io/graphql (Explorer: https://gql.bhagavadgita.io/graphiql), and displays it on browser. It is shared under free-software MIT license.

I have deliberately kept this version very simple. I saw some open-source Gita apps using Next.js but their code was quite involved. I wanted to see whether one can write very simple Hindu scripture viewer web apps using current Next.js framework without too much code and coding complexity, provided scripture content was available through an API. Note that using current Next.js framework may provide performance benefits for the web app.

I think the advantages of keeping this very simple are:
  1. As plain HTML is used without any images, the content is automatically shown suitably for devices of various screen/window widths like PC or mobile without writing any media query and related CSS code. [I must say here that I have seen quite a few Hindu scripture websites/web apps which display well on PC screens (large window width) but on mobile screens, they force the user to do a lot of horizontal scrolling to view the content, which makes it very cumbersome to view these websites on mobile. This open-source freeware app. may be of some help to such websites/web apps authors/owners & developers to migrate them to Next.js and make their sites/apps easily usable on mobile.]
  2. As default margins are used, the text content fills up the available screen/window real estate of the device and shows maximum text content to the user.
  3. A lot of content is shown on one page (e.g. all chapter summaries on one page and text & translation of all verses of a chapter on one page) thereby making it convenient for a viewer who wants to easily browse through such content without having to frequently press next/prev navigation buttons and have the page reloaded.
  4. The source code is very simple enabling developers to understand it quickly and use it as a starter or template to build more complex Gita web apps and other chapter-verse kind of web apps.
  5. Software development students and learners would find it easy to study and use the code.
Of course, there are many disadvantages with the biggest perhaps being that the user interface functionality is very minimal. Note that I am working on a simple feature to go to user specified chapter number and verse number which I hope to incorporate in this very simple app in the near future.

The app also does not have attractive frills like images and other graphics. I hope to work on another version of the app. which provides more user interface functionality (like choosing which translations & commentaries should be shown).

I decided to not use TypeScript for the files I added as that forces me to create types for the data returned by the GraphQL endpoint which makes the code somewhat more difficult to read. I initially had created them as tsx and ts files and was able to run them with development server locally. But when I deployed to Vercel, the build failed due to TypeScript errors. Rather than explore options like disabling ESLint for build, I felt that changing the files to .jsx and .js would be more in line with the objectives of my "very simple" app., and so did that.

I chose not to use Tailwind CSS to keep the app code simple.

Screenshots

Given below are a few screenshots of the app (v1) on mobile and on PC.

[On PC desktop/laptop, to open pic in larger resolution (if available), right-click on pic followed by open link (NOT image) in new tab/window. In new tab/window you may have to click on pic to zoom in.]

Version 2.0





Version 1.0






Releases

Known Issues


hn-88 on 15 Jun. 2024: "some sort of rendering issue - maybe related to unicode or other special characters"
Example - ear? skin? eyes? tongue and nose - in https://verysimplegita.vercel.app/verse/376

You could check what sort of characters the original data has, and perhaps do urlencode or something similar to fix.
----
I responded on 15 Jun. 2024: 
Thanks hn-88 for your message. The problem is with the original data itself especially with Swami Sivananda commentaries.
If you use this query, "
{
allGitaLanguages {
nodes {
language
}
}
allGitaVerses(condition: {chapterNumber: 10, verseNumber: 4}) {
nodes {
gitaCommentariesByVerseId(condition: {authorId: 16}) {
nodes {
description
authorName
authorId
}
}
}
}
}
" (copy-paste without double quotes) in https://gql.bhagavadgita.io/graphiql (in middle-top pane just below elephant icon followed by 'PostGraphiQL', copy-pasting over whatever is shown earlier in the pane) which is the GraphQL explorer for the data source, you can see that the result has the ? character issue.

I had noted the problem earlier but as the group behind the frontend app and this GraphQL data source had not responded to my messages about some issues I had with their front end app, I did not message them about this problem. Now that your raising it has resulted in this exchange which documents the issue, I think I will send them a message with this exchange as the reference. Let us see whether they respond .... Continuing in another comment ...
---
The group's front-end next.js app has the same issue: https://bhagavadgita.io/chapter/10/verse/4
But IIT Kanpur's Gita Supersite which seems to be the original source of this data, does not have this issue (instead of those ?s, we have commas) - https://www.gitasupersite.iitk.ac.in/srimad?language=dv&field_chapter_value=10&field_nsutra_value=4&ecsiva=1&etsiva=1

I had searched for this data being available directly on IIT Kanpur's Gita Supersite or some other IITK site but could not find any links to such IITK sites. My guess is that IITK is not directly sharing this data publicly. Don't know how the above mentioned group got access to the data and were able to put it up as a public data source.

Thanks again for raising the issue and your interest in this.
-----

3 Jul. 2024 Update

Added this issue as an issue in the data source related github repo: gita/bhagavad-gita-graphql#2

end - 3 Jul. 2024 Update

Notes

Is it OK to create a new ApolloClient for every query in the app.? The following article provides a way to create ApolloClient only once and reuse it for some kind of apps. In particular, it has a comment in the code, "For SSG and SSR always create a new Apollo Client". Also, the article is dated Nov. 2020 and so may not apply fully to current Next.js development. In my gita app, I am only using server components (so far) but the build produces static and dynamic pages. So I don't know whether it can be viewed as an SSG app. I don't want to spend more time on this now and so I will go with new ApolloClient for every query in the gita app. The article: Building a Next.js App with Apollo Client & Slash GraphQL, https://www.apollographql.com/blog/building-a-next-js-app-with-slash-graphql , Nov. 2020.
...

For database error handling testing, I needed to empty Next.js development server cache in VSCode (as otherwise instead of going to the database (and failing as I am not online for that testing), it gets the data from the cache and succeeds). How to clear/delete cache in NextJs?, https://stackoverflow.com/questions/68444505/how-to-clear-delete-cache-in-nextjs , July 2021 .. A comment in it advises to stop dev. server and delete .next directory. Then, on restarting dev server, .next directory is created with cache inside it.
Tried that and it worked (page failed to load due to database error as I was not online).

...

How Can i disable <Link href="" /> in next JS on various conditions, https://stackoverflow.com/questions/73555618/how-can-i-disable-link-href-in-next-js-on-various-conditions

What I have used in my code:
in css
.disabled {
  pointer-events: none;
  color: rgb(161, 158, 158);
}
-----
in jsx

      <Link href={prevHref} className={prevHref === "" ? "disabled" : ""}>
        Prev
      </Link>
----
...

Swami Sivananda commentary has ? instead of , even in graphQL endpoint, and that's shown in ui apps.
Chapter 6, Verse 3
{
  allGitaVerses(condition: {id: 236}) {
    nodes {
      gitaTranslationsByVerseId {
        nodes {
          authorName
          description
        }
      }
      gitaCommentariesByVerseId {
        nodes {
          authorName
          description
        }
      }
    }
  }
}



...

In SelectChapterVerse component, associating the label with the input results in error about id being same when the component is used twice in a page like in chapter and verse pages.

Others have faced the same issue: Avoid Duplicate id Attributes when Reusing Form Components, https://egghead.io/lessons/react-avoid-duplicate-id-attributes-when-reusing-form-components .

I was wondering whether I should use JS to come up with a unique id and whether that was OK to do. Above article seems to say it is OK. ... But I finally decided to put the burden on user-component of component to pass a suitable idSuffix prop for 2nd use of component. That fixed the Chrome Inspect warnings about id being repeated in form elements on page.
...
...

[Update: On changing the SCV from div to form, the browser shows correct error message on typing text like 4e. But the program code does not detect the error and Go button click handler runs code with React state variable being empty string.
Further, as browser is showing error messages for out of range numbers, the alert messages code does not come into play. However, I am retaining that code.]
As of now, the number fields I use do not block e or ., - etc. But the app. does not crash if that input is provided. Usually a validation alert pops up. A special case is '4e' which, I believe, is not a valid scientific notation number as it has to be followed by another digit - Strangely the input control shows 4e but the state variable (in React Developer Tools in Chrome Inspect) is blank. In this case, the app simply goes to the specified chapter instead of a verse in a chapter - not great but not too big an issue either. Note that numbers like 2e2 or 4e-2 are handled correctly with validation alert popping up. 1e1 gets converted to 10 and the app. takes use to specified chapter or verse.
The article below covers how to block e, . + - etc. from a number field in React. I may try using it in a later version of the app (for this very simple version, it will complicate the code without giving great benefit).

...

"This documentation explains how you can debug your Next.js frontend and backend code with full source maps support using either the VS Code debugger or Chrome DevTools."

In Chrome DevTools (CDT), some Next.js app sources (I think client components) are shown under _N_E entry in Sources. I could set a breakpoint and the debugger paused the program when program execution hit the breakpoint. I could check variable (other than state variables) values and step through the program. For state variable values, React Developer Tools works.

I have not yet explored Next.js backend debugging. I think I should do that in the near future.

...

After changing SCV to use form instead of div with submit process doing the validation before onSubmit handler is invoked ...
I am now trying to get a clear understanding of how the Navbar and SCV components are created/re-created as one navigates through the app.
On home page:
SCV component is rendered twice (which is think is due to strict mode in dev env.)
On typing in a number in Chapter field, SCV is rendered four times! Why is that? ... It is due to the useEffect() code with dependency of [pathname]. If that's commented then SCV renders only twice. ... But why does the useEffect() code fire? I think that's due to calls to set state functions in it. Hmm.
On going to Chapter 1, Navbar is invoked 6 times! Hmm. I also got the message, "[Violation] Forced reflow while executing JavaScript took 43ms". Note that these are NOT listed as errors or issues in Chrome DevTools. They are only messages on the browser console.

I commented out most of the navbar js code and tried again. Once again same thing. I also got the message, "[Violation] Forced reflow while executing JavaScript took 43ms". I think I had got this message earlier too but had not recorded it in this log.

Commenting out the following statement, results in 0 re-render of SCV:
const pathname = usePathname();
But, IFIRC, the following forced reflow message was still being shown: "[Violation] Forced reflow while executing JavaScript took 37ms"
Hmm. I don't think I should invest further time into understanding this issue as the re-renders seem to be related to usePathname() of nextjs.
Note that even Navbar gets rendered 6 times (along with SCV), when going from home page to chapter 1 by clicking Go.
...
As the Navbar is now in main layout page, the Navbar and associated SCV component seems to be getting created only once (and rendered many times). The impact of this is that useState variables chapterNumber and verseNumber get initialized only once. So passing changed initialChapterNumber and initialVerseNumber as props from Navbar to SCV and using them as initializer value of the useState variables chapterNumber and verseNumber in SCV, does not change the useState variable values as one moves across chapter and verse routes (from one chapter to another or one verse to another). 

To avoid repeating in SCV, the code in Navbar that figures out the chapter number and verse number from the pathname, it struck me that I could have a useEffect in SCV with dependency on initialChapterNumber and initialVerseNumber props, which sets the chapterNumber and verseNumber state variables in SCV. Before implementing it, I wanted to check if info. on the net says that's OK. Here's an article that covers that approach: How to update state when props change in React components, https://www.codemzy.com/blog/update-state-when-props-change-react.

In my limited search, I could not get a react docs page covering this approach. However, https://react.dev/reference/react/useState#storing-information-from-previous-renders covers a pattern to set a state variable ***conditionally*** during render of associated component. I could use that by having state variables in SCV to hold previous values of initialChapterNumber and initialVerseNumber props, and check if they have changed in which case I could set the chapterNumber and verseNumber state variables. But I think useEffect approach mentioned above is simpler and cleaner. 

Implemented the useEffect approach mentioned above and it works!

Some other solutions to this problem are: Share the useState variables chapterNumber and verseNumber across SCV and Navbar components. IFIRC, that would mean defining the useState variables in parent component Navbar and sharing its property and set method as props with child component SCV. 

Alternatively, we could use a centralized state manager like easy-peasy (Dave Gray React tutorial uses easy-peasy) or redux. But that would bring in a complexity that I want to avoid in this very simple app. I have not used them in Nextjs so far but little browsing on the net indicated that they can be used for client components in Nextjs.
...
To improve efficiency, I put the code in Navbar that figures out chapter and verse numbers from current pathname, and sets Prev, Next and Up links appropriately, in a useEffect() (as against in the main component body that would be executed on every render). An issue that seems to have created is that React does not re-render the component even when I change hrefs for Prev, Next and Up (all local variables) in the useEffect(). React - How to (force to) re-render a functional component?, https://stackoverflow.com/questions/46240647/react-how-to-force-to-re-render-a-functional-component/53837442#53837442 and Is there something like forceUpdate?, https://legacy.reactjs.org/docs/hooks-faq.html#is-there-something-like-forceupdate cover the issue. I think I will go for a dummy toggle state variable whose value I will change in the useEffect. Tried it and it did not work. I think the issue is useEffect changes the local variables and triggers the re-render but at that time the local variable values are lost and reset to initial values. So I have to use state variables for hrefs for Prev, Next and Up. [Same issue for chapterNumber and verseNumber variables] And now I will not need the dummy state variable.
...
To test dev version running on PC, from a mobile on same network as PC (like a WiFi network when using mobile WiFi hotspot from PC for Internet connection): First get the PC ip address on the WiFi network by running ipconfig command. Then use http://192.x.x.x:3000 on browser on mobile (where x.x.x is value obtained from ipconfig command) to access the app running on Next dev server on PC.
...

Comments